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