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.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 extends QueryBuilder {
56 protected GraphTraversal<Vertex, Vertex> traversal = null;
57 protected Admin<Vertex, Vertex> 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 = __.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 = __.start();
93 public QueryBuilder getVerticesByIndexedProperty(String key, Object value) {
95 return this.getVerticesByProperty(key, value);
102 public QueryBuilder getVerticesByIndexedProperty(String key, List<?> values) {
103 return this.getVerticesByProperty(key, values);
110 public QueryBuilder 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);
125 public QueryBuilder 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));
143 public QueryBuilder getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
144 traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType);
153 public QueryBuilder 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);
168 public QueryBuilder createDBQuery(Introspector obj) {
169 this.createKeyQuery(obj);
170 this.createContainerQuery(obj);
178 public QueryBuilder 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);
202 public QueryBuilder exactMatchQuery(Introspector obj) {
203 this.createKeyQuery(obj);
204 allPropertiesQuery(obj);
205 this.createContainerQuery(obj);
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 != null && val.getClass().equals(Long.class)) {
224 traversal.has(prop,new Integer(val.toString()));
226 traversal.has(prop, val);
239 public QueryBuilder 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);
254 * @throws NoEdgeRuleFoundException
255 * @throws AAIException
259 public QueryBuilder 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.edgeQuery(type, parent, child);
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 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.edgeQuery(type, parentObj, child);
318 public QueryBuilder union(QueryBuilder... builder) {
319 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
320 for (int i = 0; i < builder.length; i++) {
321 traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery();
323 this.traversal.union(traversals);
333 public QueryBuilder where(QueryBuilder... builder) {
334 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
335 for (int i = 0; i < builder.length; i++) {
336 this.traversal.where((GraphTraversal<Vertex, Vertex>)builder[i].getQuery());
346 * @param outType the out type
347 * @param inType the in type
348 * @throws NoEdgeRuleFoundException
349 * @throws AAIException
351 private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj) throws AAIException, NoEdgeRuleFoundException {
352 String outType = outObj.getDbName();
353 String inType = inObj.getDbName();
355 if (outObj.isContainer()) {
356 outType = outObj.getChildDBName();
358 if (inObj.isContainer()) {
359 inType = inObj.getChildDBName();
361 markParentBoundary();
362 EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
363 if (rule.getDirection().equals(Direction.OUT)) {
364 traversal.out(rule.getLabel());
366 traversal.in(rule.getLabel());
369 this.createContainerQuery(inObj);
373 public QueryBuilder limit(long amount) {
374 traversal.limit(amount);
382 public <T> T getQuery() {
383 return (T)this.traversal;
390 public QueryBuilder getParentQuery() {
392 return cloneQueryAtStep(parentStepIndex);
396 public QueryBuilder getContainerQuery() {
398 if (this.parentStepIndex == 0) {
399 return removeQueryStepsBetween(0, containerStepIndex);
401 return cloneQueryAtStep(containerStepIndex);
409 public void markParentBoundary() {
410 parentStepIndex = stepIndex;
414 public void markContainer() {
415 containerStepIndex = stepIndex;
423 public Vertex getStart() {
427 protected int getParentStepIndex() {
428 return parentStepIndex;
431 protected int getContainerStepIndex() {
432 return containerStepIndex;
435 protected int getStepIndex() {
439 protected abstract QueryBuilder cloneQueryAtStep(int index);
447 protected abstract QueryBuilder removeQueryStepsBetween(int start, int end);
449 private void executeQuery() {
451 Admin<Vertex, Vertex> admin;
453 admin = source.V(start).asAdmin();
455 admin = source.V().asAdmin();
459 TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin);
461 this.completeTraversal = admin;
465 public boolean hasNext() {
466 if (this.completeTraversal == null) {
470 return this.completeTraversal.hasNext();
474 public Vertex next() {
475 if (this.completeTraversal == null) {
479 return this.completeTraversal.next();
483 public List<Vertex> toList() {
484 if (this.completeTraversal == null) {
488 return this.completeTraversal.toList();