2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 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=========================================================
21 package org.openecomp.aai.query.builder;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.LinkedHashMap;
26 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.openecomp.aai.db.props.AAIProperties;
41 import org.openecomp.aai.exceptions.AAIException;
42 import org.openecomp.aai.introspection.Introspector;
43 import org.openecomp.aai.introspection.Loader;
44 import org.openecomp.aai.schema.enums.ObjectMetadata;
45 import org.openecomp.aai.schema.enums.PropertyMetadata;
46 import org.openecomp.aai.serialization.db.EdgeRule;
47 import org.openecomp.aai.serialization.db.EdgeRules;
48 import org.openecomp.aai.serialization.db.EdgeType;
49 import org.openecomp.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
80 * @param start the start
82 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
83 super(loader, source, start);
85 traversal = (GraphTraversal<Vertex, E>) __.__(start);
93 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, Object value) {
95 return this.getVerticesByProperty(key, value);
102 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, List<?> values) {
103 return this.getVerticesByProperty(key, values);
110 public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
112 //this is because the index is registered as an Integer
113 value = this.correctObjectType(value);
115 traversal.has(key, value);
118 return (QueryBuilder<Vertex>) this;
125 public QueryBuilder<Vertex> getVerticesByProperty(final String key, final List<?> values) {
127 //this is because the index is registered as an Integer
128 List<Object> correctedValues = new ArrayList<>();
129 for (Object item : values) {
130 correctedValues.add(this.correctObjectType(item));
133 traversal.has(key, P.within(correctedValues));
136 return (QueryBuilder<Vertex>) this;
143 public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
144 traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType);
146 return (QueryBuilder<Vertex>) this;
153 public QueryBuilder<Vertex> getTypedVerticesByMap(String type, LinkedHashMap<String, String> map) {
155 for (String key : map.keySet()) {
156 traversal.has(key, map.get(key));
159 traversal.has(AAIProperties.NODE_TYPE, type);
161 return (QueryBuilder<Vertex>) this;
168 public QueryBuilder<Vertex> createDBQuery(Introspector obj) {
169 this.createKeyQuery(obj);
170 this.createContainerQuery(obj);
171 return (QueryBuilder<Vertex>) this;
178 public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
179 Set<String> keys = obj.getKeys();
181 for (String key : keys) {
182 val = obj.getValue(key);
183 Optional<String> metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS);
184 if (metadata.isPresent()) {
185 //use the db name for the field rather than the object model
186 key = metadata.get();
189 //this is because the index is registered as an Integer
190 if (val.getClass().equals(Long.class)) {
191 traversal.has(key,new Integer(val.toString()));
193 traversal.has(key, val);
198 return (QueryBuilder<Vertex>) this;
202 public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
203 this.createKeyQuery(obj);
204 allPropertiesQuery(obj);
205 this.createContainerQuery(obj);
206 return (QueryBuilder<Vertex>) this;
209 private void allPropertiesQuery(Introspector obj) {
210 Set<String> props = obj.getProperties();
211 Set<String> keys = obj.getKeys();
213 for (String prop : props) {
214 if (obj.isSimpleType(prop) && !keys.contains(prop)) {
215 val = obj.getValue(prop);
217 Optional<String> metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS);
218 if (metadata.isPresent()) {
219 //use the db name for the field rather than the object model
220 prop = metadata.get();
222 //this is because the index is registered as an Integer
223 if (val.getClass().equals(Long.class)) {
224 traversal.has(prop,new Integer(val.toString()));
226 traversal.has(prop, val);
239 public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
240 String type = obj.getChildDBName();
241 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
242 if (abstractType != null) {
243 String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
244 traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors));
246 traversal.has(AAIProperties.NODE_TYPE, type);
250 return (QueryBuilder<Vertex>) this;
254 * @throws NoEdgeRuleFoundException
255 * @throws AAIException
259 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
260 String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT);
261 if ("true".equals(isAbstractType)) {
262 markParentBoundary();
263 traversal.union(handleAbstractEdge(type, parent, child));
266 this.edgeQueryToVertex(type, parent, child);
268 return (QueryBuilder<Vertex>) this;
272 private Traversal<Vertex, Vertex>[] handleAbstractEdge(EdgeType type, Introspector abstractParent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
273 String childName = child.getDbName();
274 String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS);
275 String[] inheritors = inheritorMetadata.split(",");
276 Traversal<Vertex, Vertex>[] unionTraversals = new Traversal[inheritors.length];
277 int traversalIndex = 0;
278 for (int i = 0; i < inheritors.length; i++) {
279 String inheritor = inheritors[i];
280 if (edgeRules.hasEdgeRule(inheritor, childName) || edgeRules.hasEdgeRule(childName, inheritor)) {
281 EdgeRule rule = edgeRules.getEdgeRule(type, inheritor, childName);
282 GraphTraversal<Vertex, Vertex> innerTraversal = __.start();
283 if (rule.getDirection().equals(Direction.OUT)) {
284 innerTraversal.out(rule.getLabel());
286 innerTraversal.in(rule.getLabel());
288 innerTraversal.has(AAIProperties.NODE_TYPE, childName);
289 unionTraversals[traversalIndex] = innerTraversal;
293 if (traversalIndex < inheritors.length) {
294 Traversal<Vertex, Vertex>[] temp = Arrays.copyOfRange(unionTraversals, 0, traversalIndex);
295 unionTraversals = temp;
297 return unionTraversals;
300 * @throws NoEdgeRuleFoundException
301 * @throws AAIException
305 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Vertex parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
307 String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null);
308 Introspector parentObj = loader.introspectorFromName(nodeType);
309 this.edgeQueryToVertex(type, parentObj, child);
310 return (QueryBuilder<Vertex>) this;
315 public QueryBuilder<Edge> getEdgesBetween(EdgeType type, String outNodeType, String inNodeType) throws AAIException {
316 Introspector outObj = loader.introspectorFromName(outNodeType);
317 Introspector inObj = loader.introspectorFromName(inNodeType);
318 this.edgeQuery(type, outObj, inObj);
320 return (QueryBuilder<Edge>)this;
327 public QueryBuilder<E> union(QueryBuilder... builder) {
328 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
329 for (int i = 0; i < builder.length; i++) {
330 traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery();
332 this.traversal.union(traversals);
342 public QueryBuilder<E> where(QueryBuilder... builder) {
343 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
344 for (int i = 0; i < builder.length; i++) {
345 this.traversal.where((GraphTraversal<Vertex, Vertex>)builder[i].getQuery());
353 public QueryBuilder<E> store(String name) {
355 this.traversal.store(name);
362 public QueryBuilder<E> cap(String name) {
363 this.traversal.cap(name);
370 public QueryBuilder<E> unfold() {
371 this.traversal.unfold();
378 public QueryBuilder<E> dedup() {
380 this.traversal.dedup();
387 public QueryBuilder<E> emit() {
389 this.traversal.emit();
397 public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
399 this.traversal.repeat((GraphTraversal<Vertex, E>)builder.getQuery());
406 public QueryBuilder<E> until(QueryBuilder<E> builder) {
407 this.traversal.until((GraphTraversal<Vertex,E>)builder.getQuery());
417 public QueryBuilder<E> simplePath(){
418 this.traversal.simplePath();
424 public QueryBuilder<Edge> outE() {
425 this.traversal.outE();
427 return (QueryBuilder<Edge>)this;
431 public QueryBuilder<Edge> inE() {
432 this.traversal.inE();
434 return (QueryBuilder<Edge>)this;
438 public QueryBuilder<Vertex> outV() {
439 this.traversal.outV();
441 return (QueryBuilder<Vertex>)this;
445 public QueryBuilder<Vertex> inV() {
446 this.traversal.inV();
448 return (QueryBuilder<Vertex>)this;
452 public QueryBuilder<E> as(String name) {
453 this.traversal.as(name);
460 public QueryBuilder<E> not(QueryBuilder<E> builder) {
461 this.traversal.not(builder.getQuery());
468 public QueryBuilder<E> select(String name) {
469 this.traversal.select(name);
479 * @param outType the out type
480 * @param inType the in type
481 * @throws NoEdgeRuleFoundException
482 * @throws AAIException
484 private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj) throws AAIException, NoEdgeRuleFoundException {
485 String outType = outObj.getDbName();
486 String inType = inObj.getDbName();
488 if (outObj.isContainer()) {
489 outType = outObj.getChildDBName();
491 if (inObj.isContainer()) {
492 inType = inObj.getChildDBName();
494 markParentBoundary();
495 EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
496 if (rule.getDirection().equals(Direction.OUT)) {
497 traversal.out(rule.getLabel());
499 traversal.in(rule.getLabel());
502 this.createContainerQuery(inObj);
509 * @param outType the out type
510 * @param inType the in type
511 * @throws NoEdgeRuleFoundException
512 * @throws AAIException
514 private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj) throws AAIException, NoEdgeRuleFoundException {
515 String outType = outObj.getDbName();
516 String inType = inObj.getDbName();
518 if (outObj.isContainer()) {
519 outType = outObj.getChildDBName();
521 if (inObj.isContainer()) {
522 inType = inObj.getChildDBName();
524 markParentBoundary();
525 EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
526 if (rule.getDirection().equals(Direction.OUT)) {
527 traversal.outE(rule.getLabel());
529 traversal.inE(rule.getLabel());
536 public QueryBuilder<E> limit(long amount) {
537 traversal.limit(amount);
545 public <E2> E2 getQuery() {
546 return (E2)this.traversal;
553 public QueryBuilder<E> getParentQuery() {
555 return cloneQueryAtStep(parentStepIndex);
559 public QueryBuilder<E> getContainerQuery() {
561 if (this.parentStepIndex == 0) {
562 return removeQueryStepsBetween(0, containerStepIndex);
564 return cloneQueryAtStep(containerStepIndex);
572 public void markParentBoundary() {
573 parentStepIndex = stepIndex;
577 public void markContainer() {
578 containerStepIndex = stepIndex;
586 public Vertex getStart() {
590 protected int getParentStepIndex() {
591 return parentStepIndex;
594 protected int getContainerStepIndex() {
595 return containerStepIndex;
598 protected int getStepIndex() {
602 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
610 protected abstract QueryBuilder<E> removeQueryStepsBetween(int start, int end);
612 private void executeQuery() {
616 this.completeTraversal = traversal.asAdmin();
618 admin = source.V().asAdmin();
619 TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin);
621 this.completeTraversal = (Admin<Vertex, E>) admin;
629 public boolean hasNext() {
630 if (this.completeTraversal == null) {
634 return this.completeTraversal.hasNext();
639 if (this.completeTraversal == null) {
643 return this.completeTraversal.next();
647 public List<E> toList() {
648 if (this.completeTraversal == null) {
652 return this.completeTraversal.toList();