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;
42 import org.openecomp.aai.db.props.AAIProperties;
43 import org.openecomp.aai.exceptions.AAIException;
44 import org.openecomp.aai.introspection.Introspector;
45 import org.openecomp.aai.introspection.Loader;
46 import org.openecomp.aai.schema.enums.ObjectMetadata;
47 import org.openecomp.aai.schema.enums.PropertyMetadata;
48 import org.openecomp.aai.serialization.db.EdgeRule;
49 import org.openecomp.aai.serialization.db.EdgeRules;
50 import org.openecomp.aai.serialization.db.EdgeType;
51 import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
54 * The Class GraphTraversalBuilder.
56 public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> {
58 protected GraphTraversal<Vertex, E> traversal = null;
59 protected Admin<Vertex, E> completeTraversal = null;
60 private EdgeRules edgeRules = EdgeRules.getInstance();
62 protected int parentStepIndex = 0;
63 protected int containerStepIndex = 0;
64 protected int stepIndex = 0;
67 * Instantiates a new graph traversal builder.
69 * @param loader the loader
71 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) {
72 super(loader, source);
74 traversal = new DefaultGraphTraversal<>();
79 * Instantiates a new graph traversal builder.
81 * @param loader the loader
82 * @param start the start
84 public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
85 super(loader, source, start);
87 traversal = new DefaultGraphTraversal<>();
95 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, Object value) {
97 return this.getVerticesByProperty(key, value);
104 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, List<?> values) {
105 return this.getVerticesByProperty(key, values);
112 public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
114 //this is because the index is registered as an Integer
115 value = this.correctObjectType(value);
117 traversal.has(key, value);
120 return (QueryBuilder<Vertex>) this;
127 public QueryBuilder<Vertex> getVerticesByProperty(final String key, final List<?> values) {
129 //this is because the index is registered as an Integer
130 List<Object> correctedValues = new ArrayList<>();
131 for (Object item : values) {
132 correctedValues.add(this.correctObjectType(item));
135 traversal.has(key, P.within(correctedValues));
138 return (QueryBuilder<Vertex>) this;
145 public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
146 traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType);
148 return (QueryBuilder<Vertex>) this;
155 public QueryBuilder<Vertex> getTypedVerticesByMap(String type, LinkedHashMap<String, String> map) {
157 for (String key : map.keySet()) {
158 traversal.has(key, map.get(key));
161 traversal.has(AAIProperties.NODE_TYPE, type);
163 return (QueryBuilder<Vertex>) this;
170 public QueryBuilder<Vertex> createDBQuery(Introspector obj) {
171 this.createKeyQuery(obj);
172 this.createContainerQuery(obj);
173 return (QueryBuilder<Vertex>) this;
180 public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
181 Set<String> keys = obj.getKeys();
183 for (String key : keys) {
184 val = obj.getValue(key);
185 Optional<String> metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS);
186 if (metadata.isPresent()) {
187 //use the db name for the field rather than the object model
188 key = metadata.get();
191 //this is because the index is registered as an Integer
192 if (val.getClass().equals(Long.class)) {
193 traversal.has(key,new Integer(val.toString()));
195 traversal.has(key, val);
200 return (QueryBuilder<Vertex>) this;
204 public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
205 this.createKeyQuery(obj);
206 allPropertiesQuery(obj);
207 this.createContainerQuery(obj);
208 return (QueryBuilder<Vertex>) this;
211 private void allPropertiesQuery(Introspector obj) {
212 Set<String> props = obj.getProperties();
213 Set<String> keys = obj.getKeys();
215 for (String prop : props) {
216 if (obj.isSimpleType(prop) && !keys.contains(prop)) {
217 val = obj.getValue(prop);
219 Optional<String> metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS);
220 if (metadata.isPresent()) {
221 //use the db name for the field rather than the object model
222 prop = metadata.get();
224 //this is because the index is registered as an Integer
225 if (val != null && val.getClass().equals(Long.class)) {
226 traversal.has(prop,new Integer(val.toString()));
228 traversal.has(prop, val);
241 public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
242 String type = obj.getChildDBName();
243 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
244 if (abstractType != null) {
245 String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
246 traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors));
248 traversal.has(AAIProperties.NODE_TYPE, type);
252 return (QueryBuilder<Vertex>) this;
256 * @throws NoEdgeRuleFoundException
257 * @throws AAIException
261 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
262 String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT);
263 if ("true".equals(isAbstractType)) {
264 markParentBoundary();
265 traversal.union(handleAbstractEdge(type, parent, child));
268 this.edgeQueryToVertex(type, parent, child);
270 return (QueryBuilder<Vertex>) this;
274 private Traversal<Vertex, Vertex>[] handleAbstractEdge(EdgeType type, Introspector abstractParent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
275 String childName = child.getDbName();
276 String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS);
277 String[] inheritors = inheritorMetadata.split(",");
278 Traversal<Vertex, Vertex>[] unionTraversals = new Traversal[inheritors.length];
279 int traversalIndex = 0;
280 for (int i = 0; i < inheritors.length; i++) {
281 String inheritor = inheritors[i];
282 if (edgeRules.hasEdgeRule(inheritor, childName) || edgeRules.hasEdgeRule(childName, inheritor)) {
283 EdgeRule rule = edgeRules.getEdgeRule(type, inheritor, childName);
284 GraphTraversal<Vertex, Vertex> innerTraversal = __.start();
285 if (rule.getDirection().equals(Direction.OUT)) {
286 innerTraversal.out(rule.getLabel());
288 innerTraversal.in(rule.getLabel());
290 innerTraversal.has(AAIProperties.NODE_TYPE, childName);
291 unionTraversals[traversalIndex] = innerTraversal;
295 if (traversalIndex < inheritors.length) {
296 Traversal<Vertex, Vertex>[] temp = Arrays.copyOfRange(unionTraversals, 0, traversalIndex);
297 unionTraversals = temp;
299 return unionTraversals;
302 * @throws NoEdgeRuleFoundException
303 * @throws AAIException
307 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Vertex parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
309 String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null);
310 Introspector parentObj = loader.introspectorFromName(nodeType);
311 this.edgeQueryToVertex(type, parentObj, child);
312 return (QueryBuilder<Vertex>) this;
317 public QueryBuilder<Edge> getEdgesBetween(EdgeType type, String outNodeType, String inNodeType) throws AAIException {
318 Introspector outObj = loader.introspectorFromName(outNodeType);
319 Introspector inObj = loader.introspectorFromName(inNodeType);
320 this.edgeQuery(type, outObj, inObj);
322 return (QueryBuilder<Edge>)this;
329 public QueryBuilder<E> union(QueryBuilder... builder) {
330 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
331 for (int i = 0; i < builder.length; i++) {
332 traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery();
334 this.traversal.union(traversals);
344 public QueryBuilder<E> where(QueryBuilder... builder) {
345 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
346 for (int i = 0; i < builder.length; i++) {
347 this.traversal.where((GraphTraversal<Vertex, Vertex>)builder[i].getQuery());
357 * @param outType the out type
358 * @param inType the in type
359 * @throws NoEdgeRuleFoundException
360 * @throws AAIException
362 private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj) throws AAIException, NoEdgeRuleFoundException {
363 String outType = outObj.getDbName();
364 String inType = inObj.getDbName();
366 if (outObj.isContainer()) {
367 outType = outObj.getChildDBName();
369 if (inObj.isContainer()) {
370 inType = inObj.getChildDBName();
372 markParentBoundary();
373 EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
374 if (rule.getDirection().equals(Direction.OUT)) {
375 traversal.out(rule.getLabel());
377 traversal.in(rule.getLabel());
380 this.createContainerQuery(inObj);
387 * @param outType the out type
388 * @param inType the in type
389 * @throws NoEdgeRuleFoundException
390 * @throws AAIException
392 private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj) throws AAIException, NoEdgeRuleFoundException {
393 String outType = outObj.getDbName();
394 String inType = inObj.getDbName();
396 if (outObj.isContainer()) {
397 outType = outObj.getChildDBName();
399 if (inObj.isContainer()) {
400 inType = inObj.getChildDBName();
402 markParentBoundary();
403 EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
404 if (rule.getDirection().equals(Direction.OUT)) {
405 traversal.outE(rule.getLabel());
407 traversal.inE(rule.getLabel());
414 public QueryBuilder<E> limit(long amount) {
415 traversal.limit(amount);
423 public <E2> E2 getQuery() {
424 return (E2)this.traversal;
431 public QueryBuilder<E> getParentQuery() {
433 return cloneQueryAtStep(parentStepIndex);
437 public QueryBuilder<E> getContainerQuery() {
439 if (this.parentStepIndex == 0) {
440 return removeQueryStepsBetween(0, containerStepIndex);
442 return cloneQueryAtStep(containerStepIndex);
450 public void markParentBoundary() {
451 parentStepIndex = stepIndex;
455 public void markContainer() {
456 containerStepIndex = stepIndex;
464 public Vertex getStart() {
468 protected int getParentStepIndex() {
469 return parentStepIndex;
472 protected int getContainerStepIndex() {
473 return containerStepIndex;
476 protected int getStepIndex() {
480 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
488 protected abstract QueryBuilder<E> removeQueryStepsBetween(int start, int end);
490 private void executeQuery() {
492 Admin<Vertex, Vertex> admin;
494 admin = source.V(start).asAdmin();
496 admin = source.V().asAdmin();
500 TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin);
502 this.completeTraversal = (Admin<Vertex, E>) admin;
506 public boolean hasNext() {
507 if (this.completeTraversal == null) {
511 return this.completeTraversal.hasNext();
516 if (this.completeTraversal == null) {
520 return this.completeTraversal.next();
524 public List<E> toList() {
525 if (this.completeTraversal == null) {
529 return this.completeTraversal.toList();