Update license files, sonar plugin and fix tests
[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 }