Initial commit with all the necessary files
[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.Vertex;
34
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 import com.google.common.base.Joiner;
46
47 /**
48  * The Class GremlinQueryBuilder.
49  */
50 public abstract class GremlinQueryBuilder extends QueryBuilder {
51         
52         private EdgeRules edgeRules = EdgeRules.getInstance();
53         private GremlinGroovyShellSingleton gremlinGroovy = GremlinGroovyShellSingleton.getInstance();
54         private GraphTraversal<?, ?> completeTraversal = null;
55         protected List<String> list = null;
56         
57         protected int parentStepIndex = 0;
58         protected int containerStepIndex = 0;
59         protected int stepIndex = 0;
60         
61         /**
62          * Instantiates a new gremlin query builder.
63          *
64          * @param loader the loader
65          */
66         public GremlinQueryBuilder(Loader loader, GraphTraversalSource source) {
67                 super(loader, source);
68                 list = new ArrayList<String>();
69         }
70         
71         /**
72          * Instantiates a new gremlin query builder.
73          *
74          * @param loader the loader
75          * @param start the start
76          */
77         public GremlinQueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
78                 super(loader, source, start);
79                 list = new ArrayList<String>();
80         }
81         
82         /**
83          * @{inheritDoc}
84          */
85         @Override
86         public QueryBuilder createDBQuery(Introspector obj) {
87                 this.createKeyQuery(obj);
88                 this.createContainerQuery(obj);
89                 return this;
90         }
91         
92         @Override
93         public QueryBuilder exactMatchQuery(Introspector obj) {
94                 // TODO not implemented because this is implementation is no longer used
95                 this.createKeyQuery(obj);
96                 //allPropertiesQuery(obj);
97                 this.createContainerQuery(obj);
98                 return this;
99         }
100         
101         /**
102          * @{inheritDoc}
103          */
104         @Override
105         public QueryBuilder getVerticesByIndexedProperty(String key, Object value) {
106                 return this.getVerticesByProperty(key, value);
107         }
108         
109         /**
110          * @{inheritDoc}
111          */
112         @Override
113         public QueryBuilder getVerticesByIndexedProperty(String key, List<?> values) {
114                 return this.getVerticesByProperty(key, values);
115         }
116
117         /**
118          * @{inheritDoc}
119          */
120         @Override
121         public QueryBuilder getVerticesByProperty(String key, Object value) {
122
123                 String term = "";
124                 if (value != null && !value.getClass().getName().equals("java.lang.String")) {
125                         term = value.toString();
126                 } else {
127                         term = "'" + value + "'";
128                 }
129                 list.add(".has('" + key + "', " + term + ")");
130                 stepIndex++;
131                 return this;
132         }
133         
134         /**
135          * @{inheritDoc}
136          */
137         @Override
138         public QueryBuilder getVerticesByProperty(String key, List<?> values) {
139
140                 String term = "";
141                 String predicate = "P.within(#!#argument#!#)";
142                 List<String> arguments = new ArrayList<>();
143                 for (Object item : values) {
144                         if (item != null && !item.getClass().getName().equals("java.lang.String")) {
145                                 arguments.add(item.toString());
146                         } else {
147                                 arguments.add("'" + item + "'");
148                         }
149                 }
150                 String argument = Joiner.on(",").join(arguments);
151                 predicate = predicate.replace("#!#argument#!#", argument);
152                 list.add(".has('" + key + "', " + predicate + ")");
153                 stepIndex++;
154                 return this;
155         }
156         
157         
158         /**
159          * @{inheritDoc}
160          */
161         @Override
162         public QueryBuilder getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
163                 /*
164                 String query = ".has('aai-node-type', '" + childType + "')";
165                 
166                 return this.processGremlinQuery(parentKey, parentValue, query);
167                 */
168                 //TODO
169                 return this;
170         }
171         
172         /**
173          * @{inheritDoc}
174          */
175         @Override
176         public QueryBuilder getTypedVerticesByMap(String type, LinkedHashMap<String, String> map) {
177                 
178                 for (String key : map.keySet()) {
179                         list.add(".has('" + key + "', '" + map.get(key) + "')");
180                         stepIndex++;
181                 }
182                 list.add(".has('aai-node-type', '" + type + "')");
183                 stepIndex++;
184                 return this;
185         }
186         
187         /**
188          * @{inheritDoc}
189          */
190         @Override
191         public QueryBuilder createKeyQuery(Introspector obj) {
192                 Set<String> keys = obj.getKeys();
193
194                 for (String key : keys) {
195                         
196                         this.getVerticesByProperty(key, obj.<Object>getValue(key));
197                         
198                 }               
199                 return this;
200         }
201         
202         /**
203          * @throws NoEdgeRuleFoundException 
204          * @throws AAIException 
205          * @{inheritDoc}
206          */
207         @Override
208         public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
209                 String parentName = parent.getDbName();
210                 String childName = child.getDbName();
211                 if (parent.isContainer()) {
212                         parentName = parent.getChildDBName();
213                 }
214                 if (child.isContainer()) {
215                         childName = child.getChildDBName();
216                 }
217                 this.edgeQuery(type, parentName, childName);
218                 return this;
219                         
220         }
221         
222         /**
223          * @throws NoEdgeRuleFoundException 
224          * @throws AAIException 
225          * @{inheritDoc}
226          */
227         @Override
228         public QueryBuilder createEdgeTraversal(EdgeType type, Vertex parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
229                 String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null);
230                 this.edgeQuery(type, nodeType, child.getDbName());
231                 
232                 return this;
233                         
234         }
235         
236         /**
237          * Edge query.
238          *
239          * @param outType the out type
240          * @param inType the in type
241          * @throws NoEdgeRuleFoundException 
242          * @throws AAIException 
243          */
244         private void edgeQuery(EdgeType type, String outType, String inType) throws AAIException, NoEdgeRuleFoundException {
245                 markParentBoundary();
246                 EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
247                 if (rule.getDirection().equals(Direction.OUT)) {
248                         list.add(".out('" + rule.getLabel() + "')");
249                 } else {
250                         list.add(".in('" + rule.getLabel() + "')");
251                 }
252                 list.add(".has('" + AAIProperties.NODE_TYPE + "', '" + inType + "')");
253                 stepIndex += 2;
254         }
255         @Override
256         public QueryBuilder limit(long amount) {
257                 list.add(".limit(" + amount + ")");
258                 return this;
259         }
260         /**
261          * @{inheritDoc}
262          */
263         @Override
264         public QueryBuilder createContainerQuery(Introspector obj) {
265                 String type = obj.getChildDBName();
266                 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
267                 if (abstractType != null) {
268                         String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
269                         String[] wrapped = new String[inheritors.length];
270                         StringBuilder command = new StringBuilder();
271                         command.append("P.within(");
272                         for (int i = 0; i < inheritors.length; i++) {
273                                 wrapped[i] = "'" + inheritors[i] + "'";
274                         }
275                         command.append(Joiner.on(",").join(wrapped));
276                         command.append(")");
277                         list.add(".has('aai-node-type', " + command + ")");
278                         
279                 } else {
280                         list.add(".has('aai-node-type', '" + type + "')");
281                 }
282                 stepIndex++;
283                 this.markContainer();
284                 return this;
285         }
286         
287         @Override
288         public QueryBuilder union(QueryBuilder... builder) {
289                 markParentBoundary();
290                 String[] traversals = new String[builder.length];
291                 StringBuilder command = new StringBuilder();
292                 for (int i = 0; i < builder.length; i++) {
293                         traversals[i] = "__" + (String)builder[i].getQuery();
294                 }
295                 command.append(".union(");
296                 command.append(Joiner.on(",").join(traversals));
297                 command.append(")");
298                 list.add(command.toString());
299                 stepIndex++;
300                 
301                 return this;
302         }
303         
304         @Override
305         public QueryBuilder where(QueryBuilder... builder) {
306                 markParentBoundary();
307                 List<String> traversals = new ArrayList<>();
308                 for (int i = 0; i < builder.length; i++) {
309                         traversals.add(".where(__" + (String)builder[i].getQuery() + ")");
310                         stepIndex++;
311                 }
312                 list.addAll(traversals);
313                 
314                 
315                 return this;
316         }
317         
318         /**
319          * @{inheritDoc}
320          */
321         @Override
322         public QueryBuilder getParentQuery() {
323                 return cloneQueryAtStep(parentStepIndex);
324         }
325         
326         @Override
327         public QueryBuilder getContainerQuery() {
328                 return cloneQueryAtStep(containerStepIndex);
329         }
330         
331         /**
332          * @{inheritDoc}
333          */
334         @Override
335         public <T> T getQuery() {
336                 StringBuilder sb = new StringBuilder();
337                 
338                 for (String piece : this.list) {
339                         sb.append(piece);
340                 }
341                 
342                 return (T)sb.toString();
343         }
344         
345         /**
346          * @{inheritDoc}
347          */
348         @Override
349         public void markParentBoundary() {
350                 parentStepIndex = stepIndex;
351         }
352         
353         @Override
354         public void markContainer() {
355                 this.containerStepIndex = stepIndex;
356         }
357         
358         protected abstract QueryBuilder cloneQueryAtStep(int index);
359         /**
360          * @{inheritDoc}
361          */
362         @Override
363         public Vertex getStart() {
364                 return this.start;
365         }
366
367         protected int getParentStepIndex() {
368                 return parentStepIndex;
369         }
370
371         protected int getContainerStepIndex() {
372                 return containerStepIndex;
373         }
374
375         protected int getStepIndex() {
376                 return stepIndex;
377         }
378         
379         private void executeQuery() {
380                 String queryString = "g" + Joiner.on("").join(list);
381                 Map<String, Object> params = new HashMap<>();
382                 if (this.start == null) {
383                         params.put("g", source.V());
384                 } else {
385                         params.put("g", source.V(this.start));
386                 }
387                 this.completeTraversal = this.gremlinGroovy.executeTraversal(queryString, params);
388         }
389         @Override
390         public boolean hasNext() {
391                 if (this.completeTraversal == null) {
392                         executeQuery();
393                 }
394                 
395                 return this.completeTraversal.hasNext();
396         }
397         
398         @Override
399         public Vertex next() {
400                 if (this.completeTraversal == null) {
401                         executeQuery();
402                 }
403                 
404                 return (Vertex)this.completeTraversal.next();
405         }
406         
407         @Override
408         public List<Vertex> toList() {
409                 if (this.completeTraversal == null) {
410                         executeQuery();
411                 }
412                 
413                 return (List<Vertex>)this.completeTraversal.toList();
414         }
415         
416 }