62ba5392f49da9d438c93f5c28c868336b71c9c9
[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.LinkedHashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30
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;
46
47 import com.google.common.base.Joiner;
48
49 /**
50  * The Class GremlinQueryBuilder.
51  */
52 public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> {
53         
54         private EdgeRules edgeRules = EdgeRules.getInstance();
55         private GremlinGroovyShellSingleton gremlinGroovy = GremlinGroovyShellSingleton.getInstance();
56         private GraphTraversal<?, ?> completeTraversal = null;
57         protected List<String> list = null;
58         
59         protected int parentStepIndex = 0;
60         protected int containerStepIndex = 0;
61         protected int stepIndex = 0;
62         
63         /**
64          * Instantiates a new gremlin query builder.
65          *
66          * @param loader the loader
67          */
68         public GremlinQueryBuilder(Loader loader, GraphTraversalSource source) {
69                 super(loader, source);
70                 list = new ArrayList<String>();
71         }
72         
73         /**
74          * Instantiates a new gremlin query builder.
75          *
76          * @param loader the loader
77          * @param start the start
78          */
79         public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
80                 super(loader, source, start);
81                 list = new ArrayList<String>();
82         }
83         
84         /**
85          * @{inheritDoc}
86          */
87         @Override
88         public QueryBuilder<Vertex> createDBQuery(Introspector obj) {
89                 this.createKeyQuery(obj);
90                 this.createContainerQuery(obj);
91                 return (QueryBuilder<Vertex>) this;
92         }
93         
94         @Override
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;
101         }
102         
103         /**
104          * @{inheritDoc}
105          */
106         @Override
107         public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, Object value) {
108                 return this.getVerticesByProperty(key, value);
109         }
110         
111         /**
112          * @{inheritDoc}
113          */
114         @Override
115         public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, List<?> values) {
116                 return this.getVerticesByProperty(key, values);
117         }
118
119         /**
120          * @{inheritDoc}
121          */
122         @Override
123         public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
124
125                 String term = "";
126                 if (value != null && !value.getClass().getName().equals("java.lang.String")) {
127                         term = value.toString();
128                 } else {
129                         term = "'" + value + "'";
130                 }
131                 list.add(".has('" + key + "', " + term + ")");
132                 stepIndex++;
133                 return (QueryBuilder<Vertex>) this;
134         }
135         
136         /**
137          * @{inheritDoc}
138          */
139         @Override
140         public QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values) {
141
142                 String term = "";
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());
148                         } else {
149                                 arguments.add("'" + item + "'");
150                         }
151                 }
152                 String argument = Joiner.on(",").join(arguments);
153                 predicate = predicate.replace("#!#argument#!#", argument);
154                 list.add(".has('" + key + "', " + predicate + ")");
155                 stepIndex++;
156                 return (QueryBuilder<Vertex>) this;
157         }
158         
159         
160         /**
161          * @{inheritDoc}
162          */
163         @Override
164         public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
165                 /*
166                 String query = ".has('aai-node-type', '" + childType + "')";
167                 
168                 return this.processGremlinQuery(parentKey, parentValue, query);
169                 */
170                 //TODO
171                 return (QueryBuilder<Vertex>) this;
172         }
173         
174         /**
175          * @{inheritDoc}
176          */
177         @Override
178         public QueryBuilder<Vertex> getTypedVerticesByMap(String type, LinkedHashMap<String, String> map) {
179                 
180                 for (String key : map.keySet()) {
181                         list.add(".has('" + key + "', '" + map.get(key) + "')");
182                         stepIndex++;
183                 }
184                 list.add(".has('aai-node-type', '" + type + "')");
185                 stepIndex++;
186                 return (QueryBuilder<Vertex>) this;
187         }
188         
189         /**
190          * @{inheritDoc}
191          */
192         @Override
193         public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
194                 Set<String> keys = obj.getKeys();
195
196                 for (String key : keys) {
197                         
198                         this.getVerticesByProperty(key, obj.<Object>getValue(key));
199                         
200                 }               
201                 return (QueryBuilder<Vertex>) this;
202         }
203         
204         /**
205          * @throws NoEdgeRuleFoundException 
206          * @throws AAIException 
207          * @{inheritDoc}
208          */
209         @Override
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();
215                 }
216                 if (child.isContainer()) {
217                         childName = child.getChildDBName();
218                 }
219                 this.edgeQueryToVertex(type, parentName, childName);
220                 return this;
221                         
222         }
223         
224         /**
225          * @throws NoEdgeRuleFoundException 
226          * @throws AAIException 
227          * @{inheritDoc}
228          */
229         @Override
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());
233                 
234                 return (QueryBuilder<Vertex>) this;
235                         
236         }
237         
238         @Override
239         public QueryBuilder<Edge> getEdgesBetween(EdgeType type, String outNodeType, String inNodeType) throws AAIException {
240                 this.edgeQuery(type, outNodeType, inNodeType);
241                 
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) 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() + "')");
258                 } else {
259                         list.add(".in('" + rule.getLabel() + "')");
260                 }
261                 stepIndex++;
262                 list.add(".has('" + AAIProperties.NODE_TYPE + "', '" + inType + "')");
263                 stepIndex++;
264                 
265         }
266         
267         /**
268          * Edge query.
269          *
270          * @param outType the out type
271          * @param inType the in type
272          * @throws NoEdgeRuleFoundException 
273          * @throws AAIException 
274          */
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() + "')");
280                 } else {
281                         list.add(".inV('" + rule.getLabel() + "')");
282                 }
283                 stepIndex++;
284                 
285         }
286         @Override
287         public QueryBuilder<E> limit(long amount) {
288                 list.add(".limit(" + amount + ")");
289                 return this;
290         }
291         /**
292          * @{inheritDoc}
293          */
294         @Override
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] + "'";
305                         }
306                         command.append(Joiner.on(",").join(wrapped));
307                         command.append(")");
308                         list.add(".has('aai-node-type', " + command + ")");
309                         
310                 } else {
311                         list.add(".has('aai-node-type', '" + type + "')");
312                 }
313                 stepIndex++;
314                 this.markContainer();
315                 return (QueryBuilder<Vertex>) this;
316         }
317         
318         @Override
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();
325                 }
326                 command.append(".union(");
327                 command.append(Joiner.on(",").join(traversals));
328                 command.append(")");
329                 list.add(command.toString());
330                 stepIndex++;
331                 
332                 return this;
333         }
334         
335         @Override
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() + ")");
341                         stepIndex++;
342                 }
343                 list.addAll(traversals);
344                 
345                 
346                 return this;
347         }
348         
349         @Override
350         public QueryBuilder<E> store(String name) {
351                 this.list.add(".store('"+ name + "')");
352                 stepIndex++;
353                 
354                 return this;
355         }
356         
357         @Override
358         public QueryBuilder<E> cap(String name) {
359                 this.list.add(".cap('"+ name + "')");
360                 stepIndex++;
361                 
362                 return this;
363         }
364         
365         @Override
366         public QueryBuilder<E> unfold() {
367                 this.list.add(".unfold()");
368                 stepIndex++;
369                 
370                 return this;
371         }
372         
373         @Override
374         public QueryBuilder<E> dedup() {
375                 this.list.add(".dedup()");
376                 stepIndex++;
377                 
378                 return this;
379         }
380         
381         @Override
382         public QueryBuilder<E> emit() {
383                 this.list.add(".emit()");
384                 stepIndex++;
385                 
386                 return this;
387         }
388         
389         @Override
390         public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
391                 this.list.add(".repeat(__" + builder.getQuery()  + ")");
392                 stepIndex++;
393                 
394                 return this;
395         }
396         
397         @Override
398         public QueryBuilder<E> until(QueryBuilder<E> builder) {
399                 this.list.add(".until(__" + builder.getQuery() + ")");
400                 stepIndex++;
401                 
402                 return this;
403         }
404         
405         /**
406          * {@inheritDoc}
407          */
408         @Override
409         public QueryBuilder<E> simplePath(){
410                 this.list.add(".simplePath()");
411                 stepIndex++;
412                 return this;
413         }
414         
415         @Override
416         public QueryBuilder<Edge> outE() {
417                 this.list.add(".outE()");
418                 stepIndex++;
419                 
420                 return (QueryBuilder<Edge>)this;
421         }
422         
423         @Override
424         public QueryBuilder<Edge> inE() {
425                 this.list.add(".inE()");
426                 stepIndex++;
427                 
428                 return (QueryBuilder<Edge>)this;
429         }
430         
431         @Override
432         public QueryBuilder<Vertex> outV() {
433                 this.list.add(".outV()");
434                 stepIndex++;
435                 
436                 return (QueryBuilder<Vertex>)this;
437         }
438         
439         @Override
440         public QueryBuilder<Vertex> inV() {
441                 this.list.add(".inV()");
442                 stepIndex++;
443                 
444                 return (QueryBuilder<Vertex>)this;
445         }
446         
447         @Override
448         public QueryBuilder<E> not(QueryBuilder<E> builder) {
449                 this.list.add(".not(" + "__" + builder.getQuery() + ")");
450                 stepIndex++;
451                 
452                 return this;
453         }
454         
455         @Override
456         public QueryBuilder<E> as(String name) {
457                 this.list.add(".as('" + name + "')");
458                 stepIndex++;
459                 
460                 return this;
461         }
462         
463         @Override
464         public QueryBuilder<E> select(String name) {
465                 this.list.add(".select('" + name + "')");
466                 stepIndex++;
467                 
468                 return this;
469         }
470         /**
471          * @{inheritDoc}
472          */
473         @Override
474         public QueryBuilder<E> getParentQuery() {
475                 return cloneQueryAtStep(parentStepIndex);
476         }
477         
478         @Override
479         public QueryBuilder<E> getContainerQuery() {
480                 return cloneQueryAtStep(containerStepIndex);
481         }
482         
483         /**
484          * @{inheritDoc}
485          */
486         @Override
487         public <T2> T2 getQuery() {
488                 StringBuilder sb = new StringBuilder();
489                 
490                 for (String piece : this.list) {
491                         sb.append(piece);
492                 }
493                 
494                 return (T2)sb.toString();
495         }
496         
497         /**
498          * @{inheritDoc}
499          */
500         @Override
501         public void markParentBoundary() {
502                 parentStepIndex = stepIndex;
503         }
504         
505         @Override
506         public void markContainer() {
507                 this.containerStepIndex = stepIndex;
508         }
509         
510         protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
511         /**
512          * @{inheritDoc}
513          */
514         @Override
515         public Vertex getStart() {
516                 return this.start;
517         }
518
519         protected int getParentStepIndex() {
520                 return parentStepIndex;
521         }
522
523         protected int getContainerStepIndex() {
524                 return containerStepIndex;
525         }
526
527         protected int getStepIndex() {
528                 return stepIndex;
529         }
530         
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());
536                 } else {
537                         params.put("g", source.V(this.start));
538                 }
539                 this.completeTraversal = this.gremlinGroovy.executeTraversal(queryString, params);
540         }
541         @Override
542         public boolean hasNext() {
543                 if (this.completeTraversal == null) {
544                         executeQuery();
545                 }
546                 
547                 return this.completeTraversal.hasNext();
548         }
549         
550         @Override
551         public E next() {
552                 if (this.completeTraversal == null) {
553                         executeQuery();
554                 }
555                 
556                 return (E)this.completeTraversal.next();
557         }
558         
559         @Override
560         public List<E> toList() {
561                 if (this.completeTraversal == null) {
562                         executeQuery();
563                 }
564                 
565                 return (List<E>)this.completeTraversal.toList();
566         }
567         
568 }