68cfd5fc345b15add2e9b7208f634e19d1f16d6b
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / query / builder / QueryBuilder.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 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 package org.onap.aai.query.builder;
21
22 import org.apache.tinkerpop.gremlin.process.traversal.Path;
23 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
24 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
25 import org.apache.tinkerpop.gremlin.structure.Edge;
26 import org.apache.tinkerpop.gremlin.structure.Vertex;
27 import org.onap.aai.config.SpringContextAware;
28 import org.onap.aai.db.props.AAIProperties;
29 import org.onap.aai.exceptions.AAIException;
30 import org.onap.aai.introspection.Introspector;
31 import org.onap.aai.introspection.Loader;
32 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
33 import org.onap.aai.parsers.query.QueryParser;
34 import org.onap.aai.parsers.query.QueryParserStrategy;
35 import org.springframework.context.ApplicationContext;
36 import org.onap.aai.edges.EdgeIngestor;
37 import org.onap.aai.edges.enums.AAIDirection;
38 import org.onap.aai.edges.enums.EdgeProperty;
39 import org.onap.aai.edges.enums.EdgeType;
40
41 import javax.ws.rs.core.MultivaluedMap;
42 import java.io.UnsupportedEncodingException;
43 import java.net.URI;
44 import java.util.Iterator;
45 import java.util.List;
46 import java.util.Map;
47
48 /**
49  * The Class QueryBuilder.
50  */
51 public abstract class QueryBuilder<E> implements Iterator<E> {
52
53         protected final GraphTraversalSource source;
54         protected QueryParserStrategy factory = null;
55         protected Loader loader = null;
56         protected EdgeIngestor edgeRules;
57         protected boolean optimize = false;
58         protected Vertex start = null;
59
60         protected int parentStepIndex = 0;
61         protected int containerStepIndex = 0;
62         protected int stepIndex = 0;
63
64         /**
65          * Instantiates a new query builder.
66          *
67          * @param loader the loader
68          */
69         public QueryBuilder(Loader loader, GraphTraversalSource source) {
70                 this.loader = loader;
71                 this.source = source;
72                 initEdgeIngestor();
73         }
74         
75         /**
76          * Instantiates a new query builder.
77          *
78          * @param loader the loader
79          * @param start the start
80          */
81         public QueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
82                 this.loader = loader;
83                 this.start = start;
84                 this.source = source;
85                 initEdgeIngestor();
86         }
87
88         public void changeLoader(Loader loader) {
89                 this.loader = loader;
90         }
91
92         protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
93
94         /**
95          * Gets the vertices by indexed property.
96          *
97          * @param key the key
98          * @param value the value
99          * @return the vertices by indexed property
100          */
101         public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, Object value) {
102                 return this.getVerticesByProperty(key, value);
103         }
104         
105         /**
106          * Gets the vertices by property.
107          *
108          * @param key the key
109          * @param value the value
110          * @return the vertices by property
111          */
112         public abstract QueryBuilder<Vertex> getVerticesByProperty(String key, Object value);
113         
114         /**
115          * filters by all the values for this property
116          * @param key
117          * @param values
118          * @return vertices that match these values
119          */
120         public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, List<?> values) {
121                 return this.getVerticesByProperty(key, values);
122         }
123
124         /**
125          * filters by all the values for this property
126          * @param key
127          * @param values
128          * @return vertices that match these values
129          */
130         public abstract QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values);
131         
132     /**
133      * Gets the vertices that have this property key.
134      *
135      * @param key the key
136      * @param value the value
137      * @return the vertices by property
138      */
139     public abstract QueryBuilder<Vertex> getVerticesByProperty(String key);
140     
141     /**
142      * Gets the vertices that do not have this property key.
143      *
144      * @param key the key
145      * @param value the value
146      * @return the vertices by property
147      */
148     public abstract QueryBuilder<Vertex> getVerticesExcludeByProperty(String key);
149
150         /**
151          * filters by elements that start with the value for this property
152          * @param key
153          * @param value
154          * @return vertices that match these values
155          */
156         public abstract QueryBuilder<Vertex> getVerticesStartsWithProperty(String key, Object value);
157
158         /**
159          * Gets the vertices that are excluded by property.
160          *
161          * @param key the key
162          * @param value the value
163          * @return the vertices by property
164          */
165         public abstract QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value);
166
167         /**
168          * filters by all the values for this property and excludes the vertices
169          * @param key
170          * @param values
171          * @return vertices that match these values
172          */
173         public QueryBuilder<Vertex> getVerticesExcludeByIndexedProperty(String key, List<?> values) {
174                 return this.getVerticesExcludeByProperty(key, values);
175         }
176
177         /**
178          * filters by all the values for this property and excludes the vertices
179          * @param key
180          * @param values
181          * @return vertices that match these values
182          */
183         public abstract QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, List<?> values);
184
185         /**
186          * filters by all the values greater than for this property  
187      * @param key
188      * @param values
189      * @return vertices that match these values
190      */
191     public abstract  QueryBuilder<Vertex> getVerticesGreaterThanProperty(String key, Object value) ;
192
193     /**
194      * filters by all the values less than for this property 
195      * @param key
196      * @param values
197      * @return vertices that match these values
198      */
199     
200     public abstract  QueryBuilder<Vertex> getVerticesLessThanProperty(String key, Object value) ;
201
202     /**
203          * Gets the child vertices from parent.
204          *
205          * @param parentKey the parent key
206          * @param parentValue the parent value
207          * @param childType the child type
208          * @return the child vertices from parent
209          */
210         public abstract QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType);
211                 
212         /**
213          * Gets the typed vertices by map.
214          *
215          * @param type the type
216          * @param map the map
217          * @return the typed vertices by map
218          */
219         public abstract QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map);
220
221         /**
222          * Creates the DB query.
223          *
224          * @param obj the obj
225          * @return the query builder
226          */
227         public QueryBuilder<Vertex> createDBQuery(Introspector obj) {
228                 this.createKeyQuery(obj);
229                 this.createContainerQuery(obj);
230                 return (QueryBuilder<Vertex>) this;
231         }
232         
233         /**
234          * Creates the key query.
235          *
236          * @param obj the obj
237          * @return the query builder
238          */
239         public abstract QueryBuilder<Vertex> createKeyQuery(Introspector obj);
240         
241         /**
242          * Creates the container query.
243          *
244          * @param obj the obj
245          * @return the query builder
246          */
247         public abstract QueryBuilder<Vertex> createContainerQuery(Introspector obj);
248         
249         /**
250          * Creates the edge traversal.
251          *
252          * @param parent the parent
253          * @param child the child
254          * @return the query builder
255          */
256         public abstract QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException;
257
258         public abstract QueryBuilder<Vertex> getVerticesByBooleanProperty(String key, Object value);
259         
260         public QueryBuilder<Vertex> getVerticesByBooleanProperty(String key, MissingOptionalParameter value) {
261                 return (QueryBuilder<Vertex>) this;
262                 }
263         /**
264          * Creates the private edge traversal.
265          *
266          * @param parent the parent
267          * @param child the child
268          * @return the query builder
269          */
270         public abstract QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException;
271
272         /**
273          * Creates the edge traversal.
274          *
275          * @param parent the parent
276          * @param child the child
277          * @return the query builder
278          */
279         public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Vertex parent, Introspector child) throws AAIException {
280                 String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null);
281                 this.createEdgeTraversal(type, nodeType, child.getDbName());
282                 return (QueryBuilder<Vertex>) this;
283         }
284
285         /**
286          *
287          * @param type
288          * @param outNodeType
289          * @param inNodeType
290          * @return
291          * @throws AAIException
292          */
293         public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, String outNodeType, String inNodeType) throws AAIException {
294                 Introspector out = loader.introspectorFromName(outNodeType);
295                 Introspector in = loader.introspectorFromName(inNodeType);
296
297                 return createEdgeTraversal(type, out, in);
298         }
299
300         /**
301          *
302          * @param edgeType
303          * @param outNodeType
304          * @param inNodeType
305          * @return
306          * @throws AAIException
307          */
308         public QueryBuilder<Vertex> createEdgeTraversal(String edgeType, String outNodeType, String inNodeType) throws AAIException {
309                 /*
310                  * When the optional parameter edgetype is sent it is a string that needs to be converted to Enum
311                  */
312                 EdgeType type = EdgeType.valueOf(edgeType);
313                 Introspector out = loader.introspectorFromName(outNodeType);
314                 Introspector in = loader.introspectorFromName(inNodeType);
315
316                 return createEdgeTraversal(type, out, in);
317         }
318         
319         /**
320          *
321          * @param MissingOptionalParameter
322          * @param outNodeType
323          * @param inNodeType
324          * @return
325          * @throws AAIException
326          */
327         public QueryBuilder<Vertex> createEdgeTraversal(MissingOptionalParameter edgeType, String outNodeType, String inNodeType) throws AAIException {
328                 /*
329                  * When no optional parameter edgetype is sent get all edges between the 2 nodetypes
330                  */
331                 return this.createEdgeTraversal(outNodeType, inNodeType);       
332         }
333         
334         public QueryBuilder<Vertex> createEdgeTraversal(String outNodeType, String inNodeType) throws AAIException {
335
336                 Introspector out = loader.introspectorFromName(outNodeType);
337                 Introspector in = loader.introspectorFromName(inNodeType);
338
339                 QueryBuilder<Vertex> cousinBuilder = null;
340                 QueryBuilder<Vertex> treeBuilder   = null;
341                 QueryBuilder<Vertex> queryBuilder  = null;
342
343                 try {
344                         cousinBuilder = this.newInstance().createEdgeTraversal(EdgeType.COUSIN, out, in);
345                 } catch (AAIException e) {
346                 }
347
348                 if(cousinBuilder != null){
349                         try {
350                                 treeBuilder = this.newInstance().createEdgeTraversal(EdgeType.TREE, out, in);
351                         } catch (AAIException e) {
352                         }
353                         if(treeBuilder != null){
354                                 queryBuilder = this.union(new QueryBuilder[]{cousinBuilder, treeBuilder});
355                         } else {
356                                 queryBuilder = this.union(new QueryBuilder[]{cousinBuilder});
357                         }
358                 } else {
359                         treeBuilder = this.newInstance().createEdgeTraversal(EdgeType.TREE, out, in);
360                         queryBuilder = this.union(new QueryBuilder[]{treeBuilder});
361                 }
362
363
364                 return queryBuilder;
365         }
366
367         public QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, String outNodeType, String inNodeType) throws AAIException {
368                 Introspector out = loader.introspectorFromName(outNodeType);
369                 Introspector in = loader.introspectorFromName(inNodeType);
370                 return createPrivateEdgeTraversal(type, out, in);
371         }
372
373         /**
374          *
375          * @param type
376          * @param outNodeType
377          * @param inNodeType
378          * @param labels
379          * @return
380          * @throws AAIException
381          */
382         public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, String outNodeType, String inNodeType, List<String> labels) throws AAIException {
383                 Introspector out = loader.introspectorFromName(outNodeType);
384                 Introspector in = loader.introspectorFromName(inNodeType);
385
386                 return createEdgeTraversalWithLabels(type, out, in, labels);
387         }
388
389         /**
390          *
391          * @param type
392          * @param out
393          * @param in
394          * @param labels
395          * @return
396          */
397         public abstract QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List<String> labels) throws AAIException;
398
399         /**
400          *
401          * @param type
402          * @param outNodeType
403          * @param inNodeType
404          * @return
405          * @throws AAIException
406          */
407         public QueryBuilder<Edge> getEdgesBetween(EdgeType type, String outNodeType, String inNodeType) throws AAIException {
408                 this.getEdgesBetweenWithLabels(type, outNodeType, inNodeType, null);
409
410                 return (QueryBuilder<Edge>)this;
411
412         }
413         /**
414          *
415          * @param type
416          * @param outNodeType
417          * @param inNodeType
418          * @param labels
419          * @return
420          * @throws AAIException
421          */
422         public abstract QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, List<String> labels) throws AAIException;
423
424         /**
425          * Creates the query from URI.
426          *
427          * @param uri the uri
428          * @return the query parser
429          * @throws UnsupportedEncodingException the unsupported encoding exception
430          * @throws AAIException the AAI exception
431          */
432         public abstract QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException;
433         
434         /**
435          * Creates the query from URI.
436          *
437          * @param uri the uri
438          * @param queryParams the query params
439          * @return the query parser
440          * @throws UnsupportedEncodingException the unsupported encoding exception
441          * @throws AAIException the AAI exception
442          */
443         public abstract QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams) throws UnsupportedEncodingException, AAIException;
444
445         /**
446          * Creates a queryparser from a given object name.
447          * 
448          * @param objName - name of the object type as it appears in the database
449          * @return
450          */
451         public abstract QueryParser createQueryFromObjectName(String objName);
452         
453         /**
454          * Creates the query from relationship.
455          *
456          * @param relationship the relationship
457          * @return the query parser
458          * @throws UnsupportedEncodingException the unsupported encoding exception
459          * @throws AAIException the AAI exception
460          */
461         public abstract QueryParser createQueryFromRelationship(Introspector relationship) throws UnsupportedEncodingException, AAIException;
462
463         /**
464          * Gets the parent query.
465          *
466          * @return the parent query
467          */
468         public abstract QueryBuilder<E> getParentQuery();
469         
470         /**
471          * Gets the query.
472          *
473          * @return the query
474          */
475         public abstract <E2> E2 getQuery();
476         
477         /**
478          * Form boundary.
479          */
480         public abstract void markParentBoundary();
481         
482         public abstract QueryBuilder<E> limit(long amount);
483
484         /**
485          * New instance.
486          *
487          * @param start the start
488          * @return the query builder
489          */
490         public abstract QueryBuilder<E> newInstance(Vertex start);
491         
492         /**
493          * New instance.
494          *
495          * @return the query builder
496          */
497         public abstract QueryBuilder<E> newInstance();
498         
499         /**
500          * Gets the start.
501          *
502          * @return the start
503          */
504         public abstract Vertex getStart();
505
506         protected Object correctObjectType(Object obj) {
507                 
508                 if (obj != null && obj.getClass().equals(Long.class)) {
509                         return new Integer(obj.toString());
510                 }
511                 
512                 return obj;
513         }
514         /**
515          * uses all fields in the introspector to create a query
516          * 
517          * @param obj
518          * @return
519          */
520         public abstract QueryBuilder<Vertex> exactMatchQuery(Introspector obj);
521
522         /**
523          * lets you join any number of QueryBuilders
524          * <b>be careful about starting with a union it will not use indexes</b>
525          * @param builder
526          * @return
527          */
528         public abstract QueryBuilder<E> union(QueryBuilder<E>... builder);
529         
530         public abstract QueryBuilder<E> where(QueryBuilder<E>... builder);
531         
532         public abstract QueryBuilder<E> or(QueryBuilder<E>... builder);
533         
534         public abstract QueryBuilder<E> store(String name);
535         public abstract QueryBuilder<E> cap(String name);
536         public abstract QueryBuilder<E> unfold();
537         public abstract QueryBuilder<E> dedup();
538         public abstract QueryBuilder<E> emit();
539         public abstract QueryBuilder<E> repeat(QueryBuilder<E> builder);
540         public abstract QueryBuilder<Edge> outE();
541         public abstract QueryBuilder<Edge> inE();
542         public abstract QueryBuilder<Vertex> inV();
543         public abstract QueryBuilder<Vertex> outV();
544         public abstract QueryBuilder<E> not(QueryBuilder<E> builder);
545         public abstract QueryBuilder<E> as(String name);
546         public abstract QueryBuilder<E> select(String name);
547         public abstract QueryBuilder<E> select(String... names);
548         public abstract QueryBuilder<E> until(QueryBuilder<E> builder);
549         public abstract QueryBuilder<E> groupCount();
550         public abstract QueryBuilder<E> by(String name);
551         public abstract QueryBuilder<E> both();
552         public abstract QueryBuilder<Tree> tree();
553         
554         /**
555          * Used to prevent the traversal from repeating its path through the graph.
556          * See http://tinkerpop.apache.org/docs/3.0.1-incubating/#simplepath-step for more info.
557          * 
558          * @return a QueryBuilder with the simplePath step appended to its traversal
559          */
560         public abstract QueryBuilder<E> simplePath();
561
562         /**
563          *
564          * @return QueryBuilder with the path step appended to its traversal
565          */
566         public abstract QueryBuilder<Path> path();
567         
568         public abstract void markContainer();
569
570         public abstract QueryBuilder<E> getContainerQuery();
571
572         public abstract List<E> toList();
573
574         /**
575          * Used to skip step if there is an optional property missing.
576          * @param key
577          * @param value
578          * @return
579          */
580         public QueryBuilder<Vertex> getVerticesByProperty(String key, MissingOptionalParameter value) {
581                 return (QueryBuilder<Vertex>) this;
582         }
583
584         /**
585          * TODO the edge direction is hardcoded here, make it more generic
586          * Returns the parent edge of the vertex
587          * @return
588          */
589         public QueryBuilder<Edge> getParentEdge() {
590                 this.outE().has(EdgeProperty.CONTAINS.toString(), AAIDirection.IN.toString());
591                 return (QueryBuilder<Edge>)this;
592         }
593
594         /**
595          * TODO the edge direction is hardcoded here, make it more generic
596          * Returns the parent vertex of the vertex
597          * @return
598          */
599         public QueryBuilder<Vertex> getParentVertex() {
600                 this.getParentEdge().inV();
601                 return (QueryBuilder<Vertex>)this;
602         }
603
604         protected abstract QueryBuilder<Edge> has(String key, String value);
605         
606         protected void initEdgeIngestor() {
607                 //TODO proper spring wiring, but that requires a lot of refactoring so for now we have this
608                 ApplicationContext ctx = SpringContextAware.getApplicationContext();
609                 EdgeIngestor ei = ctx.getBean(EdgeIngestor.class);
610                 setEdgeIngestor(ei);
611         }
612         
613         protected void setEdgeIngestor(EdgeIngestor ei) {
614                 this.edgeRules = ei;
615         }
616
617         public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, Object value) {
618                 return getVerticesByProperty(key, value);
619         }
620
621     public QueryBuilder<Vertex> getVerticesByNumberProperty(String key) {
622         return getVerticesByProperty(key);
623     }
624     
625     public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, MissingOptionalParameter value) {
626                 return getVerticesByProperty(key, value);
627         }
628 }