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.DefaultGraphTraversal;
34 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
35 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
36 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
37 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
38 import org.apache.tinkerpop.gremlin.structure.Direction;
39 import org.apache.tinkerpop.gremlin.structure.Edge;
40 import org.apache.tinkerpop.gremlin.structure.Vertex;
41 import org.openecomp.aai.db.props.AAIProperties;
42 import org.openecomp.aai.exceptions.AAIException;
43 import org.openecomp.aai.introspection.Introspector;
44 import org.openecomp.aai.introspection.Loader;
45 import org.openecomp.aai.schema.enums.ObjectMetadata;
46 import org.openecomp.aai.schema.enums.PropertyMetadata;
47 import org.openecomp.aai.serialization.db.EdgeRule;
48 import org.openecomp.aai.serialization.db.EdgeRules;
49 import org.openecomp.aai.serialization.db.EdgeType;
50 import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
53 * The Class GraphTraversalBuilder.
55 public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> {
57 protected GraphTraversal<Vertex, E> traversal = null;
58 protected Admin<Vertex, E> completeTraversal = null;
59 private EdgeRules edgeRules = EdgeRules.getInstance();
61 protected int parentStepIndex = 0;
62 protected int containerStepIndex = 0;
63 protected int stepIndex = 0;
66 * Instantiates a new graph traversal builder.
68 * @param loader the loader
70 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) {
71 super(loader, source);
73 traversal = new DefaultGraphTraversal<>();
78 * Instantiates a new graph traversal builder.
80 * @param loader the loader
81 * @param start the start
83 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
84 super(loader, source, start);
86 traversal = new DefaultGraphTraversal<>();
94 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, Object value) {
96 return this.getVerticesByProperty(key, value);
103 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, List<?> values) {
104 return this.getVerticesByProperty(key, values);
111 public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
113 //this is because the index is registered as an Integer
114 value = this.correctObjectType(value);
116 traversal.has(key, value);
119 return (QueryBuilder<Vertex>) this;
126 public QueryBuilder<Vertex> getVerticesByProperty(final String key, final List<?> values) {
128 //this is because the index is registered as an Integer
129 List<Object> correctedValues = new ArrayList<>();
130 for (Object item : values) {
131 correctedValues.add(this.correctObjectType(item));
134 traversal.has(key, P.within(correctedValues));
137 return (QueryBuilder<Vertex>) this;
144 public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
145 traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType);
147 return (QueryBuilder<Vertex>) this;
154 public QueryBuilder<Vertex> getTypedVerticesByMap(String type, LinkedHashMap<String, String> map) {
156 for (String key : map.keySet()) {
157 traversal.has(key, map.get(key));
160 traversal.has(AAIProperties.NODE_TYPE, type);
162 return (QueryBuilder<Vertex>) this;
169 public QueryBuilder<Vertex> createDBQuery(Introspector obj) {
170 this.createKeyQuery(obj);
171 this.createContainerQuery(obj);
172 return (QueryBuilder<Vertex>) this;
179 public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
180 Set<String> keys = obj.getKeys();
182 for (String key : keys) {
183 val = obj.getValue(key);
184 Optional<String> metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS);
185 if (metadata.isPresent()) {
186 //use the db name for the field rather than the object model
187 key = metadata.get();
190 //this is because the index is registered as an Integer
191 if (val.getClass().equals(Long.class)) {
192 traversal.has(key,new Integer(val.toString()));
194 traversal.has(key, val);
199 return (QueryBuilder<Vertex>) this;
203 public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
204 this.createKeyQuery(obj);
205 allPropertiesQuery(obj);
206 this.createContainerQuery(obj);
207 return (QueryBuilder<Vertex>) this;
210 private void allPropertiesQuery(Introspector obj) {
211 Set<String> props = obj.getProperties();
212 Set<String> keys = obj.getKeys();
214 for (String prop : props) {
215 if (obj.isSimpleType(prop) && !keys.contains(prop)) {
216 val = obj.getValue(prop);
218 Optional<String> metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS);
219 if (metadata.isPresent()) {
220 //use the db name for the field rather than the object model
221 prop = metadata.get();
223 //this is because the index is registered as an Integer
224 if (val != null && val.getClass().equals(Long.class)) {
225 traversal.has(prop,new Integer(val.toString()));
227 traversal.has(prop, val);
240 public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
241 String type = obj.getChildDBName();
242 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
243 if (abstractType != null) {
244 String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
245 traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors));
247 traversal.has(AAIProperties.NODE_TYPE, type);
251 return (QueryBuilder<Vertex>) this;
255 * @throws NoEdgeRuleFoundException
256 * @throws AAIException
260 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
261 String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT);
262 if ("true".equals(isAbstractType)) {
263 markParentBoundary();
264 traversal.union(handleAbstractEdge(type, parent, child));
267 this.edgeQueryToVertex(type, parent, child);
269 return (QueryBuilder<Vertex>) this;
273 private Traversal<Vertex, Vertex>[] handleAbstractEdge(EdgeType type, Introspector abstractParent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
274 String childName = child.getDbName();
275 String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS);
276 String[] inheritors = inheritorMetadata.split(",");
277 Traversal<Vertex, Vertex>[] unionTraversals = new Traversal[inheritors.length];
278 int traversalIndex = 0;
279 for (int i = 0; i < inheritors.length; i++) {
280 String inheritor = inheritors[i];
281 if (edgeRules.hasEdgeRule(inheritor, childName) || edgeRules.hasEdgeRule(childName, inheritor)) {
282 EdgeRule rule = edgeRules.getEdgeRule(type, inheritor, childName);
283 GraphTraversal<Vertex, Vertex> innerTraversal = __.start();
284 if (rule.getDirection().equals(Direction.OUT)) {
285 innerTraversal.out(rule.getLabel());
287 innerTraversal.in(rule.getLabel());
289 innerTraversal.has(AAIProperties.NODE_TYPE, childName);
290 unionTraversals[traversalIndex] = innerTraversal;
294 if (traversalIndex < inheritors.length) {
295 Traversal<Vertex, Vertex>[] temp = Arrays.copyOfRange(unionTraversals, 0, traversalIndex);
296 unionTraversals = temp;
298 return unionTraversals;
301 * @throws NoEdgeRuleFoundException
302 * @throws AAIException
306 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Vertex parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
308 String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null);
309 Introspector parentObj = loader.introspectorFromName(nodeType);
310 this.edgeQueryToVertex(type, parentObj, child);
311 return (QueryBuilder<Vertex>) this;
316 public QueryBuilder<Edge> getEdgesBetween(EdgeType type, String outNodeType, String inNodeType) throws AAIException {
317 Introspector outObj = loader.introspectorFromName(outNodeType);
318 Introspector inObj = loader.introspectorFromName(inNodeType);
319 this.edgeQuery(type, outObj, inObj);
321 return (QueryBuilder<Edge>)this;
328 public QueryBuilder<E> union(QueryBuilder... builder) {
329 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
330 for (int i = 0; i < builder.length; i++) {
331 traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery();
333 this.traversal.union(traversals);
343 public QueryBuilder<E> where(QueryBuilder... builder) {
344 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
345 for (int i = 0; i < builder.length; i++) {
346 this.traversal.where((GraphTraversal<Vertex, Vertex>)builder[i].getQuery());
354 public QueryBuilder<E> store(String name) {
356 this.traversal.store(name);
363 public QueryBuilder<E> cap(String name) {
364 this.traversal.cap(name);
371 public QueryBuilder<E> unfold() {
372 this.traversal.unfold();
379 public QueryBuilder<E> dedup() {
381 this.traversal.dedup();
388 public QueryBuilder<E> emit() {
390 this.traversal.emit();
398 public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
400 this.traversal.repeat((GraphTraversal<Vertex, E>)builder.getQuery());
407 public QueryBuilder<Edge> outE() {
408 this.traversal.outE();
410 return (QueryBuilder<Edge>)this;
414 public QueryBuilder<Edge> inE() {
415 this.traversal.inE();
417 return (QueryBuilder<Edge>)this;
421 public QueryBuilder<Vertex> outV() {
422 this.traversal.outV();
424 return (QueryBuilder<Vertex>)this;
428 public QueryBuilder<Vertex> inV() {
429 this.traversal.inV();
431 return (QueryBuilder<Vertex>)this;
435 public QueryBuilder<E> as(String name) {
436 this.traversal.as(name);
443 public QueryBuilder<E> not(QueryBuilder<E> builder) {
444 this.traversal.not(builder.getQuery());
451 public QueryBuilder<E> select(String name) {
452 this.traversal.select(name);
462 * @param outType the out type
463 * @param inType the in type
464 * @throws NoEdgeRuleFoundException
465 * @throws AAIException
467 private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj) throws AAIException, NoEdgeRuleFoundException {
468 String outType = outObj.getDbName();
469 String inType = inObj.getDbName();
471 if (outObj.isContainer()) {
472 outType = outObj.getChildDBName();
474 if (inObj.isContainer()) {
475 inType = inObj.getChildDBName();
477 markParentBoundary();
478 EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
479 if (rule.getDirection().equals(Direction.OUT)) {
480 traversal.out(rule.getLabel());
482 traversal.in(rule.getLabel());
485 this.createContainerQuery(inObj);
492 * @param outType the out type
493 * @param inType the in type
494 * @throws NoEdgeRuleFoundException
495 * @throws AAIException
497 private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj) throws AAIException, NoEdgeRuleFoundException {
498 String outType = outObj.getDbName();
499 String inType = inObj.getDbName();
501 if (outObj.isContainer()) {
502 outType = outObj.getChildDBName();
504 if (inObj.isContainer()) {
505 inType = inObj.getChildDBName();
507 markParentBoundary();
508 EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
509 if (rule.getDirection().equals(Direction.OUT)) {
510 traversal.outE(rule.getLabel());
512 traversal.inE(rule.getLabel());
519 public QueryBuilder<E> limit(long amount) {
520 traversal.limit(amount);
528 public <E2> E2 getQuery() {
529 return (E2)this.traversal;
536 public QueryBuilder<E> getParentQuery() {
538 return cloneQueryAtStep(parentStepIndex);
542 public QueryBuilder<E> getContainerQuery() {
544 if (this.parentStepIndex == 0) {
545 return removeQueryStepsBetween(0, containerStepIndex);
547 return cloneQueryAtStep(containerStepIndex);
555 public void markParentBoundary() {
556 parentStepIndex = stepIndex;
560 public void markContainer() {
561 containerStepIndex = stepIndex;
569 public Vertex getStart() {
573 protected int getParentStepIndex() {
574 return parentStepIndex;
577 protected int getContainerStepIndex() {
578 return containerStepIndex;
581 protected int getStepIndex() {
585 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
593 protected abstract QueryBuilder<E> removeQueryStepsBetween(int start, int end);
595 private void executeQuery() {
597 Admin<Vertex, Vertex> admin;
599 admin = source.V(start).asAdmin();
601 admin = source.V().asAdmin();
605 TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin);
607 this.completeTraversal = (Admin<Vertex, E>) admin;
611 public boolean hasNext() {
612 if (this.completeTraversal == null) {
616 return this.completeTraversal.hasNext();
621 if (this.completeTraversal == null) {
625 return this.completeTraversal.next();
629 public List<E> toList() {
630 if (this.completeTraversal == null) {
634 return this.completeTraversal.toList();