f2eaa91f93c1edf1ff1da5eb6ebbbecb09157ec8
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / query / builder / GremlinQueryBuilder.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
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
10  *
11  *    http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  *
20  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  */
22 package org.onap.aai.query.builder;
23
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
31 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
32 import org.apache.tinkerpop.gremlin.structure.Direction;
33 import org.apache.tinkerpop.gremlin.structure.Edge;
34 import org.apache.tinkerpop.gremlin.structure.Vertex;
35 import org.onap.aai.db.props.AAIProperties;
36 import org.onap.aai.exceptions.AAIException;
37 import org.onap.aai.introspection.Introspector;
38 import org.onap.aai.introspection.Loader;
39 import org.onap.aai.restcore.search.GremlinGroovyShellSingleton;
40 import org.onap.aai.schema.enums.ObjectMetadata;
41 import org.onap.aai.serialization.db.EdgeRule;
42 import org.onap.aai.serialization.db.EdgeRules;
43 import org.onap.aai.serialization.db.EdgeType;
44 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
45
46 import com.google.common.base.Joiner;
47
48 /**
49  * The Class GremlinQueryBuilder.
50  */
51 public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> {
52         
53         private EdgeRules edgeRules = EdgeRules.getInstance();
54         private GremlinGroovyShellSingleton gremlinGroovy = GremlinGroovyShellSingleton.getInstance();
55         private GraphTraversal<?, ?> completeTraversal = null;
56         protected List<String> list = null;
57         
58         protected int parentStepIndex = 0;
59         protected int containerStepIndex = 0;
60         protected int stepIndex = 0;
61         
62         /**
63          * Instantiates a new gremlin query builder.
64          *
65          * @param loader the loader
66          */
67         public GremlinQueryBuilder(Loader loader, GraphTraversalSource source) {
68                 super(loader, source);
69                 list = new ArrayList<>();
70         }
71         
72         /**
73          * Instantiates a new graph gremlin builder.
74          *
75          * @param loader the loader
76          */
77         public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, EdgeRules edgeRules) {
78                 super(loader, source);
79                 this.edgeRules = edgeRules;
80                 list = new ArrayList<>();
81                 
82         }
83         
84         /**
85          * Instantiates a new gremlin query builder.
86          *
87          * @param loader the loader
88          * @param start the start
89          */
90         public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
91                 super(loader, source, start);
92                 list = new ArrayList<>();
93         }
94         
95         /**
96          * Instantiates a new graph gremlin builder.
97          *
98          * @param loader the loader
99          * @param start the start
100          */
101         public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start, EdgeRules edgeRules) {
102                 super(loader, source, start);
103                 this.edgeRules = edgeRules;
104                 list = new ArrayList<>();
105                 
106         }
107         
108         @Override
109         public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
110                 // TODO not implemented because this is implementation is no longer used
111                 this.createKeyQuery(obj);
112                 this.createContainerQuery(obj);
113                 return (QueryBuilder<Vertex>) this;
114         }
115
116         /**
117          * @{inheritDoc}
118          */
119         @Override
120         public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
121
122                 String term = "";
123                 if (value != null && !(value instanceof String) ) {
124                         term = value.toString();
125                 } else {
126                         term = "'" + value + "'";
127                 }
128                 list.add(".has('" + key + "', " + term + ")");
129                 stepIndex++;
130                 return (QueryBuilder<Vertex>) this;
131         }
132         
133         /**
134          * @{inheritDoc}
135          */
136         @Override
137         public QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values) {
138
139                 String term = "";
140                 String predicate = "P.within(#!#argument#!#)";
141                 List<String> arguments = new ArrayList<>();
142                 for (Object item : values) {
143                         if (item != null && !(item instanceof String)) {
144                                 arguments.add(item.toString());
145                         } else {
146                                 arguments.add("'" + item + "'");
147                         }
148                 }
149                 String argument = Joiner.on(",").join(arguments);
150                 predicate = predicate.replace("#!#argument#!#", argument);
151                 list.add(".has('" + key + "', " + predicate + ")");
152                 stepIndex++;
153                 return (QueryBuilder<Vertex>) this;
154         }
155         
156         
157         /**
158          * @{inheritDoc}
159          */
160         @Override
161         public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
162                 /*
163                 String query = ".has('aai-node-type', '" + childType + "')";
164                 
165                 return this.processGremlinQuery(parentKey, parentValue, query);
166                 */
167                 //TODO
168                 return (QueryBuilder<Vertex>) this;
169         }
170         
171         /**
172          * @{inheritDoc}
173          */
174         @Override
175         public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) {
176                 
177                 for (Map.Entry<String, String> es : map.entrySet()) {
178                         list.add(".has('" + es.getKey() + "', '" + es.getValue() + "')");
179                         stepIndex++;
180                 }
181                 list.add(".has('aai-node-type', '" + type + "')");
182                 stepIndex++;
183                 return (QueryBuilder<Vertex>) this;
184         }
185         
186         /**
187          * @{inheritDoc}
188          */
189         @Override
190         public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
191                 Set<String> keys = obj.getKeys();
192
193                 for (String key : keys) {
194                         
195                         this.getVerticesByProperty(key, obj.<Object>getValue(key));
196                         
197                 }               
198                 return (QueryBuilder<Vertex>) this;
199         }
200         
201         /**
202          * @throws NoEdgeRuleFoundException 
203          * @throws AAIException 
204          * @{inheritDoc}
205          */
206         @Override
207         public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException {
208                 String parentName = parent.getDbName();
209                 String childName = child.getDbName();
210                 if (parent.isContainer()) {
211                         parentName = parent.getChildDBName();
212                 }
213                 if (child.isContainer()) {
214                         childName = child.getChildDBName();
215                 }
216                 this.edgeQueryToVertex(type, parentName, childName, null);
217                 return this;
218                         
219         }
220
221         /**
222          *
223          * @{inheritDoc}
224          */
225         @Override
226         public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List<String> labels) throws AAIException {
227                 String parentName = out.getDbName();
228                 String childName = in.getDbName();
229                 if (out.isContainer()) {
230                         parentName = out.getChildDBName();
231                 }
232                 if (in.isContainer()) {
233                         childName = in.getChildDBName();
234                 }
235                 this.edgeQueryToVertex(type, parentName, childName, labels);
236                 return (QueryBuilder<Vertex>) this;
237         }
238
239
240         public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, List<String> labels) throws AAIException {
241                 this.edgeQuery(type, outNodeType, inNodeType, labels);
242                 return (QueryBuilder<Edge>)this;
243         }
244
245         /**
246          * Edge query.
247          *
248          * @param outType the out type
249          * @param inType the in type
250          * @throws NoEdgeRuleFoundException
251          * @throws AAIException
252          */
253         private void edgeQueryToVertex(EdgeType type, String outType, String inType, List<String> labels) throws AAIException {
254                 markParentBoundary();
255                 Map<String, EdgeRule> rules;
256                 if (labels == null) {
257                         rules = edgeRules.getEdgeRules(type, outType, inType);
258                 } else {
259                         rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
260                 }
261
262                 final List<String> inLabels = new ArrayList<>();
263                 final List<String> outLabels = new ArrayList<>();
264
265                 rules.forEach((k, edgeRule) -> {
266                         if (labels != null && !labels.contains(k)) {
267                                 return;
268                         } else {
269                                 if (edgeRule.getDirection().equals(Direction.IN)) {
270                                         inLabels.add(edgeRule.getLabel());
271                                 } else {
272                                         outLabels.add(edgeRule.getLabel());
273                                 }
274                         }
275                 });
276
277                 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
278                         list.add(".out('" + String.join("','", outLabels) + "')");
279                 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
280                         list.add(".in('" + String.join("','", inLabels) + "')");
281                 } else {
282                         list.add(".union(__.in('" + String.join("','", inLabels) + "')" + ", __.out('" + String.join("','", outLabels) + "'))");
283                 }
284                 stepIndex++;
285                 list.add(".has('" + AAIProperties.NODE_TYPE + "', '" + inType + "')");
286                 stepIndex++;
287                 
288         }
289         
290         /**
291          * Edge query.
292          *
293          * @param outType the out type
294          * @param inType the in type
295          * @throws NoEdgeRuleFoundException 
296          * @throws AAIException 
297          */
298         private void edgeQuery(EdgeType type, String outType, String inType, List<String> labels) throws AAIException {
299                 markParentBoundary();
300                 Map<String, EdgeRule> rules;
301                 if (labels == null) {
302                         rules = edgeRules.getEdgeRules(type, outType, inType);
303                 } else {
304                         rules = edgeRules.getEdgeRulesWithLabels(type, outType, inType, labels);
305                 }
306                 
307                 final List<String> inLabels = new ArrayList<>();
308                 final List<String> outLabels = new ArrayList<>();
309
310                 rules.forEach((k, edgeRule) -> {
311                         if (labels != null && !labels.contains(k)) {
312                                 return;
313                         } else {
314                                 if (edgeRule.getDirection().equals(Direction.IN)) {
315                                         inLabels.add(edgeRule.getLabel());
316                                 } else {
317                                         outLabels.add(edgeRule.getLabel());
318                                 }
319                         }
320                 });
321
322                 if (inLabels.isEmpty() && !outLabels.isEmpty()) {
323                         list.add(".outE('" + String.join("','", outLabels) + "')");
324                 } else if (outLabels.isEmpty() && !inLabels.isEmpty()) {
325                         list.add(".inE('" + String.join("','", inLabels) + "')");
326                 } else {
327                         list.add(".union(__.inE('" + String.join("','", inLabels) + "')" + ", __.outE('" + String.join("','", outLabels) + "'))");
328                 }
329                 
330                 stepIndex++;
331                 
332         }
333         @Override
334         public QueryBuilder<E> limit(long amount) {
335                 list.add(".limit(" + amount + ")");
336                 return this;
337         }
338         /**
339          * @{inheritDoc}
340          */
341         @Override
342         public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
343                 String type = obj.getChildDBName();
344                 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
345                 if (abstractType != null) {
346                         String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
347                         String[] wrapped = new String[inheritors.length];
348                         StringBuilder command = new StringBuilder();
349                         command.append("P.within(");
350                         for (int i = 0; i < inheritors.length; i++) {
351                                 wrapped[i] = "'" + inheritors[i] + "'";
352                         }
353                         command.append(Joiner.on(",").join(wrapped));
354                         command.append(")");
355                         list.add(".has('aai-node-type', " + command + ")");
356                         
357                 } else {
358                         list.add(".has('aai-node-type', '" + type + "')");
359                 }
360                 stepIndex++;
361                 this.markContainer();
362                 return (QueryBuilder<Vertex>) this;
363         }
364         
365         @Override
366         public QueryBuilder<E> union(QueryBuilder<E>... builder) {
367                 markParentBoundary();
368                 String[] traversals = new String[builder.length];
369                 StringBuilder command = new StringBuilder();
370                 for (int i = 0; i < builder.length; i++) {
371                         traversals[i] = "__" + (String)builder[i].getQuery();
372                 }
373                 command.append(".union(");
374                 command.append(Joiner.on(",").join(traversals));
375                 command.append(")");
376                 list.add(command.toString());
377                 stepIndex++;
378                 
379                 return this;
380         }
381         
382         @Override
383         public QueryBuilder<E> where(QueryBuilder<E>... builder) {
384                 markParentBoundary();
385                 List<String> traversals = new ArrayList<>();
386                 for (int i = 0; i < builder.length; i++) {
387                         traversals.add(".where(__" + (String)builder[i].getQuery() + ")");
388                         stepIndex++;
389                 }
390                 list.addAll(traversals);
391                 
392                 
393                 return this;
394         }
395         
396         @Override
397         public QueryBuilder<E> store(String name) {
398                 this.list.add(".store('"+ name + "')");
399                 stepIndex++;
400                 
401                 return this;
402         }
403         
404         @Override
405         public QueryBuilder<E> cap(String name) {
406                 this.list.add(".cap('"+ name + "')");
407                 stepIndex++;
408                 
409                 return this;
410         }
411         
412         @Override
413         public QueryBuilder<E> unfold() {
414                 this.list.add(".unfold()");
415                 stepIndex++;
416                 
417                 return this;
418         }
419         
420         @Override
421         public QueryBuilder<E> dedup() {
422                 this.list.add(".dedup()");
423                 stepIndex++;
424                 
425                 return this;
426         }
427         
428         @Override
429         public QueryBuilder<E> emit() {
430                 this.list.add(".emit()");
431                 stepIndex++;
432                 
433                 return this;
434         }
435         
436         @Override
437         public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
438                 this.list.add(".repeat(__" + builder.getQuery()  + ")");
439                 stepIndex++;
440                 
441                 return this;
442         }
443         
444         @Override
445         public QueryBuilder<E> until(QueryBuilder<E> builder) {
446                 this.list.add(".until(__" + builder.getQuery() + ")");
447                 stepIndex++;
448                 
449                 return this;
450         }
451         
452         /**
453          * {@inheritDoc}
454          */
455         @Override
456         public QueryBuilder<E> simplePath(){
457                 this.list.add(".simplePath()");
458                 stepIndex++;
459                 return this;
460         }
461         
462         @Override
463         public QueryBuilder<Edge> outE() {
464                 this.list.add(".outE()");
465                 stepIndex++;
466                 
467                 return (QueryBuilder<Edge>)this;
468         }
469         
470         @Override
471         public QueryBuilder<Edge> inE() {
472                 this.list.add(".inE()");
473                 stepIndex++;
474                 
475                 return (QueryBuilder<Edge>)this;
476         }
477         
478         @Override
479         public QueryBuilder<Vertex> outV() {
480                 this.list.add(".outV()");
481                 stepIndex++;
482                 
483                 return (QueryBuilder<Vertex>)this;
484         }
485         
486         @Override
487         public QueryBuilder<Vertex> inV() {
488                 this.list.add(".inV()");
489                 stepIndex++;
490                 
491                 return (QueryBuilder<Vertex>)this;
492         }
493         
494         @Override
495         public QueryBuilder<E> not(QueryBuilder<E> builder) {
496                 this.list.add(".not(" + "__" + builder.getQuery() + ")");
497                 stepIndex++;
498                 
499                 return this;
500         }
501         
502         @Override
503         public QueryBuilder<E> as(String name) {
504                 this.list.add(".as('" + name + "')");
505                 stepIndex++;
506                 
507                 return this;
508         }
509         
510         @Override
511         public QueryBuilder<E> select(String name) {
512                 this.list.add(".select('" + name + "')");
513                 stepIndex++;
514                 
515                 return this;
516         }
517         /**
518          * @{inheritDoc}
519          */
520         @Override
521         public QueryBuilder<E> getParentQuery() {
522                 return cloneQueryAtStep(parentStepIndex);
523         }
524         
525         @Override
526         public QueryBuilder<E> getContainerQuery() {
527                 return cloneQueryAtStep(containerStepIndex);
528         }
529         
530         /**
531          * @{inheritDoc}
532          */
533         @Override
534         public <T2> T2 getQuery() {
535                 StringBuilder sb = new StringBuilder();
536                 
537                 for (String piece : this.list) {
538                         sb.append(piece);
539                 }
540                 
541                 return (T2)sb.toString();
542         }
543         
544         /**
545          * @{inheritDoc}
546          */
547         @Override
548         public void markParentBoundary() {
549                 parentStepIndex = stepIndex;
550         }
551         
552         @Override
553         public void markContainer() {
554                 this.containerStepIndex = stepIndex;
555         }
556         
557         protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
558         /**
559          * @{inheritDoc}
560          */
561         @Override
562         public Vertex getStart() {
563                 return this.start;
564         }
565
566         protected int getParentStepIndex() {
567                 return parentStepIndex;
568         }
569
570         protected int getContainerStepIndex() {
571                 return containerStepIndex;
572         }
573
574         protected int getStepIndex() {
575                 return stepIndex;
576         }
577         
578         private void executeQuery() {
579                 String queryString = "g" + Joiner.on("").join(list);
580                 Map<String, Object> params = new HashMap<>();
581                 if (this.start == null) {
582                         params.put("g", source.V());
583                 } else {
584                         params.put("g", source.V(this.start));
585                 }
586                 this.completeTraversal = this.gremlinGroovy.executeTraversal(queryString, params);
587         }
588         @Override
589         public boolean hasNext() {
590                 if (this.completeTraversal == null) {
591                         executeQuery();
592                 }
593                 
594                 return this.completeTraversal.hasNext();
595         }
596         
597         @Override
598         public E next() {
599                 if (this.completeTraversal == null) {
600                         executeQuery();
601                 }
602                 
603                 return (E)this.completeTraversal.next();
604         }
605         
606         @Override
607         public List<E> toList() {
608                 if (this.completeTraversal == null) {
609                         executeQuery();
610                 }
611                 
612                 return (List<E>)this.completeTraversal.toList();
613         }
614         
615 }