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.HashMap;
26 import java.util.LinkedHashMap;
27 import java.util.List;
31 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
32 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
33 import org.apache.tinkerpop.gremlin.structure.Direction;
34 import org.apache.tinkerpop.gremlin.structure.Edge;
35 import org.apache.tinkerpop.gremlin.structure.Vertex;
36 import org.onap.aai.db.props.AAIProperties;
37 import org.onap.aai.exceptions.AAIException;
38 import org.onap.aai.introspection.Introspector;
39 import org.onap.aai.introspection.Loader;
40 import org.onap.aai.restcore.search.GremlinGroovyShellSingleton;
41 import org.onap.aai.schema.enums.ObjectMetadata;
42 import org.onap.aai.serialization.db.EdgeRule;
43 import org.onap.aai.serialization.db.EdgeRules;
44 import org.onap.aai.serialization.db.EdgeType;
45 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
47 import com.google.common.base.Joiner;
50 * The Class GremlinQueryBuilder.
52 public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> {
54 private EdgeRules edgeRules = EdgeRules.getInstance();
55 private GremlinGroovyShellSingleton gremlinGroovy = GremlinGroovyShellSingleton.getInstance();
56 private GraphTraversal<?, ?> completeTraversal = null;
57 protected List<String> list = null;
59 protected int parentStepIndex = 0;
60 protected int containerStepIndex = 0;
61 protected int stepIndex = 0;
64 * Instantiates a new gremlin query builder.
66 * @param loader the loader
68 public GremlinQueryBuilder(Loader loader, GraphTraversalSource source) {
69 super(loader, source);
70 list = new ArrayList<String>();
74 * Instantiates a new gremlin query builder.
76 * @param loader the loader
77 * @param start the start
79 public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
80 super(loader, source, start);
81 list = new ArrayList<String>();
88 public QueryBuilder<Vertex> createDBQuery(Introspector obj) {
89 this.createKeyQuery(obj);
90 this.createContainerQuery(obj);
91 return (QueryBuilder<Vertex>) this;
95 public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
96 // TODO not implemented because this is implementation is no longer used
97 this.createKeyQuery(obj);
98 //allPropertiesQuery(obj);
99 this.createContainerQuery(obj);
100 return (QueryBuilder<Vertex>) this;
107 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, Object value) {
108 return this.getVerticesByProperty(key, value);
115 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, List<?> values) {
116 return this.getVerticesByProperty(key, values);
123 public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
126 if (value != null && !value.getClass().getName().equals("java.lang.String")) {
127 term = value.toString();
129 term = "'" + value + "'";
131 list.add(".has('" + key + "', " + term + ")");
133 return (QueryBuilder<Vertex>) this;
140 public QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values) {
143 String predicate = "P.within(#!#argument#!#)";
144 List<String> arguments = new ArrayList<>();
145 for (Object item : values) {
146 if (item != null && !item.getClass().getName().equals("java.lang.String")) {
147 arguments.add(item.toString());
149 arguments.add("'" + item + "'");
152 String argument = Joiner.on(",").join(arguments);
153 predicate = predicate.replace("#!#argument#!#", argument);
154 list.add(".has('" + key + "', " + predicate + ")");
156 return (QueryBuilder<Vertex>) this;
164 public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
166 String query = ".has('aai-node-type', '" + childType + "')";
168 return this.processGremlinQuery(parentKey, parentValue, query);
171 return (QueryBuilder<Vertex>) this;
178 public QueryBuilder<Vertex> getTypedVerticesByMap(String type, LinkedHashMap<String, String> map) {
180 for (String key : map.keySet()) {
181 list.add(".has('" + key + "', '" + map.get(key) + "')");
184 list.add(".has('aai-node-type', '" + type + "')");
186 return (QueryBuilder<Vertex>) this;
193 public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
194 Set<String> keys = obj.getKeys();
196 for (String key : keys) {
198 this.getVerticesByProperty(key, obj.<Object>getValue(key));
201 return (QueryBuilder<Vertex>) this;
205 * @throws NoEdgeRuleFoundException
206 * @throws AAIException
210 public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
211 String parentName = parent.getDbName();
212 String childName = child.getDbName();
213 if (parent.isContainer()) {
214 parentName = parent.getChildDBName();
216 if (child.isContainer()) {
217 childName = child.getChildDBName();
219 this.edgeQueryToVertex(type, parentName, childName);
225 * @throws NoEdgeRuleFoundException
226 * @throws AAIException
230 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Vertex parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
231 String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null);
232 this.edgeQueryToVertex(type, nodeType, child.getDbName());
234 return (QueryBuilder<Vertex>) this;
239 public QueryBuilder<Edge> getEdgesBetween(EdgeType type, String outNodeType, String inNodeType) throws AAIException {
240 this.edgeQuery(type, outNodeType, inNodeType);
242 return (QueryBuilder<Edge>)this;
248 * @param outType the out type
249 * @param inType the in type
250 * @throws NoEdgeRuleFoundException
251 * @throws AAIException
253 private void edgeQueryToVertex(EdgeType type, String outType, String inType) throws AAIException, NoEdgeRuleFoundException {
254 markParentBoundary();
255 EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
256 if (rule.getDirection().equals(Direction.OUT)) {
257 list.add(".out('" + rule.getLabel() + "')");
259 list.add(".in('" + rule.getLabel() + "')");
262 list.add(".has('" + AAIProperties.NODE_TYPE + "', '" + inType + "')");
270 * @param outType the out type
271 * @param inType the in type
272 * @throws NoEdgeRuleFoundException
273 * @throws AAIException
275 private void edgeQuery(EdgeType type, String outType, String inType) throws AAIException, NoEdgeRuleFoundException {
276 markParentBoundary();
277 EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
278 if (rule.getDirection().equals(Direction.OUT)) {
279 list.add(".outE('" + rule.getLabel() + "')");
281 list.add(".inV('" + rule.getLabel() + "')");
287 public QueryBuilder<E> limit(long amount) {
288 list.add(".limit(" + amount + ")");
295 public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
296 String type = obj.getChildDBName();
297 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
298 if (abstractType != null) {
299 String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
300 String[] wrapped = new String[inheritors.length];
301 StringBuilder command = new StringBuilder();
302 command.append("P.within(");
303 for (int i = 0; i < inheritors.length; i++) {
304 wrapped[i] = "'" + inheritors[i] + "'";
306 command.append(Joiner.on(",").join(wrapped));
308 list.add(".has('aai-node-type', " + command + ")");
311 list.add(".has('aai-node-type', '" + type + "')");
314 this.markContainer();
315 return (QueryBuilder<Vertex>) this;
319 public QueryBuilder<E> union(QueryBuilder<E>... builder) {
320 markParentBoundary();
321 String[] traversals = new String[builder.length];
322 StringBuilder command = new StringBuilder();
323 for (int i = 0; i < builder.length; i++) {
324 traversals[i] = "__" + (String)builder[i].getQuery();
326 command.append(".union(");
327 command.append(Joiner.on(",").join(traversals));
329 list.add(command.toString());
336 public QueryBuilder<E> where(QueryBuilder<E>... builder) {
337 markParentBoundary();
338 List<String> traversals = new ArrayList<>();
339 for (int i = 0; i < builder.length; i++) {
340 traversals.add(".where(__" + (String)builder[i].getQuery() + ")");
343 list.addAll(traversals);
350 public QueryBuilder<E> store(String name) {
351 this.list.add(".store('"+ name + "')");
358 public QueryBuilder<E> cap(String name) {
359 this.list.add(".cap('"+ name + "')");
366 public QueryBuilder<E> unfold() {
367 this.list.add(".unfold()");
374 public QueryBuilder<E> dedup() {
375 this.list.add(".dedup()");
382 public QueryBuilder<E> emit() {
383 this.list.add(".emit()");
390 public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
391 this.list.add(".repeat(__" + builder.getQuery() + ")");
398 public QueryBuilder<E> until(QueryBuilder<E> builder) {
399 this.list.add(".until(__" + builder.getQuery() + ")");
409 public QueryBuilder<E> simplePath(){
410 this.list.add(".simplePath()");
416 public QueryBuilder<Edge> outE() {
417 this.list.add(".outE()");
420 return (QueryBuilder<Edge>)this;
424 public QueryBuilder<Edge> inE() {
425 this.list.add(".inE()");
428 return (QueryBuilder<Edge>)this;
432 public QueryBuilder<Vertex> outV() {
433 this.list.add(".outV()");
436 return (QueryBuilder<Vertex>)this;
440 public QueryBuilder<Vertex> inV() {
441 this.list.add(".inV()");
444 return (QueryBuilder<Vertex>)this;
448 public QueryBuilder<E> not(QueryBuilder<E> builder) {
449 this.list.add(".not(" + "__" + builder.getQuery() + ")");
456 public QueryBuilder<E> as(String name) {
457 this.list.add(".as('" + name + "')");
464 public QueryBuilder<E> select(String name) {
465 this.list.add(".select('" + name + "')");
474 public QueryBuilder<E> getParentQuery() {
475 return cloneQueryAtStep(parentStepIndex);
479 public QueryBuilder<E> getContainerQuery() {
480 return cloneQueryAtStep(containerStepIndex);
487 public <T2> T2 getQuery() {
488 StringBuilder sb = new StringBuilder();
490 for (String piece : this.list) {
494 return (T2)sb.toString();
501 public void markParentBoundary() {
502 parentStepIndex = stepIndex;
506 public void markContainer() {
507 this.containerStepIndex = stepIndex;
510 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
515 public Vertex getStart() {
519 protected int getParentStepIndex() {
520 return parentStepIndex;
523 protected int getContainerStepIndex() {
524 return containerStepIndex;
527 protected int getStepIndex() {
531 private void executeQuery() {
532 String queryString = "g" + Joiner.on("").join(list);
533 Map<String, Object> params = new HashMap<>();
534 if (this.start == null) {
535 params.put("g", source.V());
537 params.put("g", source.V(this.start));
539 this.completeTraversal = this.gremlinGroovy.executeTraversal(queryString, params);
542 public boolean hasNext() {
543 if (this.completeTraversal == null) {
547 return this.completeTraversal.hasNext();
552 if (this.completeTraversal == null) {
556 return (E)this.completeTraversal.next();
560 public List<E> toList() {
561 if (this.completeTraversal == null) {
565 return (List<E>)this.completeTraversal.toList();