Add the vnf changes
[aai/aai-common.git] / aai-core / src / main / java / org / openecomp / aai / query / builder / GraphTraversalBuilder.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.Arrays;
25 import java.util.LinkedHashMap;
26 import java.util.List;
27 import java.util.Optional;
28 import java.util.Set;
29
30 import org.apache.tinkerpop.gremlin.process.traversal.P;
31 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
32 import org.apache.tinkerpop.gremlin.process.traversal.Traversal.Admin;
33 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal;
34 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
35 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
36 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
37 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
38 import org.apache.tinkerpop.gremlin.structure.Direction;
39 import org.apache.tinkerpop.gremlin.structure.Edge;
40 import org.apache.tinkerpop.gremlin.structure.Vertex;
41 import org.openecomp.aai.db.props.AAIProperties;
42 import org.openecomp.aai.exceptions.AAIException;
43 import org.openecomp.aai.introspection.Introspector;
44 import org.openecomp.aai.introspection.Loader;
45 import org.openecomp.aai.schema.enums.ObjectMetadata;
46 import org.openecomp.aai.schema.enums.PropertyMetadata;
47 import org.openecomp.aai.serialization.db.EdgeRule;
48 import org.openecomp.aai.serialization.db.EdgeRules;
49 import org.openecomp.aai.serialization.db.EdgeType;
50 import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
51
52 /**
53  * The Class GraphTraversalBuilder.
54  */
55 public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> {
56
57         protected GraphTraversal<Vertex, E> traversal = null;
58         protected Admin<Vertex, E> completeTraversal = null;
59         private EdgeRules edgeRules = EdgeRules.getInstance();
60         
61         protected int parentStepIndex = 0;
62         protected int containerStepIndex = 0;
63         protected int stepIndex = 0;
64         
65         /**
66          * Instantiates a new graph traversal builder.
67          *
68          * @param loader the loader
69          */
70         public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) {
71                 super(loader, source);
72                 
73                 traversal = new DefaultGraphTraversal<>();
74                 
75         }
76         
77         /**
78          * Instantiates a new graph traversal builder.
79          *
80          * @param loader the loader
81          * @param start the start
82          */
83         public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
84                 super(loader, source, start);
85                 
86                 traversal = new DefaultGraphTraversal<>();
87                 
88         }
89
90         /**
91          * @{inheritDoc}
92          */
93         @Override
94         public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, Object value) {
95         
96                 return this.getVerticesByProperty(key, value);
97         }
98
99         /**
100          * @{inheritDoc}
101          */
102         @Override
103         public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, List<?> values) {
104                 return this.getVerticesByProperty(key, values);
105         }
106         
107         /**
108          * @{inheritDoc}
109          */
110         @Override
111         public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) {
112                 
113                 //this is because the index is registered as an Integer
114                 value = this.correctObjectType(value);
115                 
116                 traversal.has(key, value);
117                 
118                 stepIndex++;
119                 return (QueryBuilder<Vertex>) this;
120         }
121         
122         /**
123          * @{inheritDoc}
124          */
125         @Override
126         public QueryBuilder<Vertex> getVerticesByProperty(final String key, final List<?> values) {
127                 
128                 //this is because the index is registered as an Integer
129                 List<Object> correctedValues = new ArrayList<>();
130                 for (Object item : values) {
131                         correctedValues.add(this.correctObjectType(item));
132                 }
133                 
134                 traversal.has(key, P.within(correctedValues));
135                 
136                 stepIndex++;
137                 return (QueryBuilder<Vertex>) this;
138         }
139
140         /**
141          * @{inheritDoc}
142          */
143         @Override
144         public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) {
145                 traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType);
146                 stepIndex++;
147                 return (QueryBuilder<Vertex>) this;
148         }
149
150         /**
151          * @{inheritDoc}
152          */
153         @Override
154         public QueryBuilder<Vertex> getTypedVerticesByMap(String type, LinkedHashMap<String, String> map) {
155                 
156                 for (String key : map.keySet()) {
157                         traversal.has(key, map.get(key));
158                         stepIndex++;
159                 }
160                 traversal.has(AAIProperties.NODE_TYPE, type);
161                 stepIndex++;
162                 return (QueryBuilder<Vertex>) this;
163         }
164
165         /**
166          * @{inheritDoc}
167          */
168         @Override
169         public QueryBuilder<Vertex> createDBQuery(Introspector obj) {
170                 this.createKeyQuery(obj);
171                 this.createContainerQuery(obj);
172                 return (QueryBuilder<Vertex>) this;
173         }
174
175         /**
176          * @{inheritDoc}
177          */
178         @Override
179         public QueryBuilder<Vertex> createKeyQuery(Introspector obj) {
180                 Set<String> keys = obj.getKeys();
181                 Object val;
182                 for (String key : keys) {
183                         val = obj.getValue(key);
184                         Optional<String> metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS);
185                         if (metadata.isPresent()) {
186                                 //use the db name for the field rather than the object model
187                                 key = metadata.get();
188                         }
189                         if (val != null) {
190                                 //this is because the index is registered as an Integer
191                                 if (val.getClass().equals(Long.class)) {
192                                         traversal.has(key,new Integer(val.toString()));
193                                 } else {
194                                         traversal.has(key, val);
195                                 }
196                                 stepIndex++;
197                         }
198                 }
199                 return (QueryBuilder<Vertex>) this;
200         }
201
202         @Override
203         public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) {
204                 this.createKeyQuery(obj);
205                 allPropertiesQuery(obj);
206                 this.createContainerQuery(obj);
207                 return (QueryBuilder<Vertex>) this;
208         }
209         
210         private void allPropertiesQuery(Introspector obj) {
211                 Set<String> props = obj.getProperties();
212                 Set<String> keys = obj.getKeys();
213                 Object val;
214                 for (String prop : props) {
215                         if (obj.isSimpleType(prop) && !keys.contains(prop)) {
216                                 val = obj.getValue(prop);
217                                 if (val != null) {
218                                         Optional<String> metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS);
219                                         if (metadata.isPresent()) {
220                                                 //use the db name for the field rather than the object model
221                                                 prop = metadata.get();
222                                         }
223                                         //this is because the index is registered as an Integer
224                                         if (val != null && val.getClass().equals(Long.class)) {
225                                                 traversal.has(prop,new Integer(val.toString()));
226                                         } else {
227                                                 traversal.has(prop, val);
228                                         }
229                                         stepIndex++;
230                                 }
231                         }
232                 }
233         }
234         
235         /**
236          * @{inheritDoc}
237          */
238         @Override
239         
240         public QueryBuilder<Vertex> createContainerQuery(Introspector obj) {
241                 String type = obj.getChildDBName();
242                 String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT);
243                 if (abstractType != null) {
244                         String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(",");
245                         traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors));
246                 } else {
247                         traversal.has(AAIProperties.NODE_TYPE, type);
248                 }
249                 stepIndex++;
250                 markContainer();
251                 return (QueryBuilder<Vertex>) this;
252         }
253
254         /**
255          * @throws NoEdgeRuleFoundException 
256          * @throws AAIException 
257          * @{inheritDoc}
258          */
259         @Override
260         public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
261                 String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT);
262                 if ("true".equals(isAbstractType)) {
263                         markParentBoundary();
264                         traversal.union(handleAbstractEdge(type, parent, child));
265                         stepIndex += 1;
266                 } else {
267                         this.edgeQueryToVertex(type, parent, child);
268                 }
269                 return (QueryBuilder<Vertex>) this;
270                         
271         }
272         
273         private Traversal<Vertex, Vertex>[] handleAbstractEdge(EdgeType type, Introspector abstractParent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
274                 String childName = child.getDbName();
275                 String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS);
276                 String[] inheritors = inheritorMetadata.split(",");
277                 Traversal<Vertex, Vertex>[] unionTraversals = new Traversal[inheritors.length];
278                 int traversalIndex = 0;
279                 for (int i = 0; i < inheritors.length; i++) {
280                         String inheritor = inheritors[i];
281                         if (edgeRules.hasEdgeRule(inheritor, childName) || edgeRules.hasEdgeRule(childName, inheritor)) {
282                                 EdgeRule rule = edgeRules.getEdgeRule(type, inheritor, childName);
283                                 GraphTraversal<Vertex, Vertex> innerTraversal = __.start();
284                                 if (rule.getDirection().equals(Direction.OUT)) {
285                                         innerTraversal.out(rule.getLabel());
286                                 } else {
287                                         innerTraversal.in(rule.getLabel());
288                                 }
289                                 innerTraversal.has(AAIProperties.NODE_TYPE, childName);
290                                 unionTraversals[traversalIndex] = innerTraversal;
291                                 traversalIndex++;
292                         }
293                 }
294                 if (traversalIndex < inheritors.length) {
295                         Traversal<Vertex, Vertex>[] temp = Arrays.copyOfRange(unionTraversals, 0, traversalIndex);
296                         unionTraversals = temp;
297                 }
298                 return unionTraversals;
299         }
300         /**
301          * @throws NoEdgeRuleFoundException 
302          * @throws AAIException 
303          * @{inheritDoc}
304          */
305         @Override
306         public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Vertex parent, Introspector child) throws AAIException, NoEdgeRuleFoundException {
307                 
308                 String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null);
309                 Introspector parentObj = loader.introspectorFromName(nodeType);
310                 this.edgeQueryToVertex(type, parentObj, child);
311                 return (QueryBuilder<Vertex>) this;
312                         
313         }
314         
315         @Override
316         public QueryBuilder<Edge> getEdgesBetween(EdgeType type, String outNodeType, String inNodeType) throws AAIException {
317                 Introspector outObj = loader.introspectorFromName(outNodeType);
318                 Introspector inObj = loader.introspectorFromName(inNodeType);
319                 this.edgeQuery(type, outObj, inObj);
320                 
321                 return (QueryBuilder<Edge>)this;
322
323         }
324         /**
325          * @{inheritDoc}
326          */
327         @Override
328         public QueryBuilder<E> union(QueryBuilder... builder) {
329                 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
330                 for (int i = 0; i < builder.length; i++) {
331                         traversals[i] = (GraphTraversal<Vertex, Vertex>)builder[i].getQuery();
332                 }
333                 this.traversal.union(traversals);
334                 stepIndex++;
335                 
336                 return this;
337         }
338         
339         /**
340          * @{inheritDoc}
341          */
342         @Override
343         public QueryBuilder<E> where(QueryBuilder... builder) {
344                 GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length];
345                 for (int i = 0; i < builder.length; i++) {
346                         this.traversal.where((GraphTraversal<Vertex, Vertex>)builder[i].getQuery());
347                         stepIndex++;
348                 }
349                 
350                 return this;
351         }
352         
353         @Override
354         public QueryBuilder<E> store(String name) {
355                 
356                 this.traversal.store(name);
357                 stepIndex++;
358                 
359                 return this;
360         }
361         
362         @Override
363         public QueryBuilder<E> cap(String name) {
364                 this.traversal.cap(name);
365                 stepIndex++;
366                 
367                 return this;
368         }
369         
370         @Override
371         public QueryBuilder<E> unfold() {
372                 this.traversal.unfold();
373                 stepIndex++;
374                         
375                 return this;
376         }
377         
378         @Override
379         public QueryBuilder<E> dedup() {
380                 
381                 this.traversal.dedup();
382                 stepIndex++;
383                 
384                 return this;
385         }
386         
387         @Override
388         public QueryBuilder<E> emit() {
389                 
390                 this.traversal.emit();
391                 stepIndex++;
392                 
393                 return this;
394                 
395         }
396         
397         @Override
398         public QueryBuilder<E> repeat(QueryBuilder<E> builder) {
399                 
400                 this.traversal.repeat((GraphTraversal<Vertex, E>)builder.getQuery());
401                 stepIndex++;
402
403                 return this;
404         }
405         
406         @Override
407         public QueryBuilder<Edge> outE() {
408                 this.traversal.outE();
409                 stepIndex++;
410                 return (QueryBuilder<Edge>)this;
411         }
412         
413         @Override
414         public QueryBuilder<Edge> inE() {
415                 this.traversal.inE();
416                 stepIndex++;
417                 return (QueryBuilder<Edge>)this;
418         }
419         
420         @Override
421         public QueryBuilder<Vertex> outV() {
422                 this.traversal.outV();
423                 stepIndex++;
424                 return (QueryBuilder<Vertex>)this;
425         }
426         
427         @Override
428         public QueryBuilder<Vertex> inV() {
429                 this.traversal.inV();
430                 stepIndex++;
431                 return (QueryBuilder<Vertex>)this;
432         }
433         
434         @Override
435         public QueryBuilder<E> as(String name) {
436                 this.traversal.as(name);
437                 
438                 stepIndex++;
439                 return this;
440         }
441         
442         @Override
443         public QueryBuilder<E> not(QueryBuilder<E> builder) {
444                 this.traversal.not(builder.getQuery());
445                 
446                 stepIndex++;
447                 return this;
448         }
449         
450         @Override
451         public QueryBuilder<E> select(String name) {
452                 this.traversal.select(name);
453                 
454                 stepIndex++;
455                 
456                 return this;
457         }
458         
459         /**
460          * Edge query.
461          *
462          * @param outType the out type
463          * @param inType the in type
464          * @throws NoEdgeRuleFoundException 
465          * @throws AAIException 
466          */
467         private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj) throws AAIException, NoEdgeRuleFoundException {
468                 String outType = outObj.getDbName();
469                 String inType = inObj.getDbName();
470                 
471                 if (outObj.isContainer()) {
472                         outType = outObj.getChildDBName();
473                 }
474                 if (inObj.isContainer()) {
475                         inType = inObj.getChildDBName();
476                 }
477                 markParentBoundary();
478                 EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
479                 if (rule.getDirection().equals(Direction.OUT)) {
480                         traversal.out(rule.getLabel());
481                 } else {
482                         traversal.in(rule.getLabel());
483                 }
484                 stepIndex++;
485                 this.createContainerQuery(inObj);
486                 
487         }
488         
489         /**
490          * Edge query.
491          *
492          * @param outType the out type
493          * @param inType the in type
494          * @throws NoEdgeRuleFoundException 
495          * @throws AAIException 
496          */
497         private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj) throws AAIException, NoEdgeRuleFoundException {
498                 String outType = outObj.getDbName();
499                 String inType = inObj.getDbName();
500                 
501                 if (outObj.isContainer()) {
502                         outType = outObj.getChildDBName();
503                 }
504                 if (inObj.isContainer()) {
505                         inType = inObj.getChildDBName();
506                 }
507                 markParentBoundary();
508                 EdgeRule rule = edgeRules.getEdgeRule(type, outType, inType);
509                 if (rule.getDirection().equals(Direction.OUT)) {
510                         traversal.outE(rule.getLabel());
511                 } else {
512                         traversal.inE(rule.getLabel());
513                 }
514                 stepIndex++;
515                 
516         }
517         
518         @Override
519         public QueryBuilder<E> limit(long amount) {
520                 traversal.limit(amount);
521                 return this;
522         }
523
524         /**
525          * @{inheritDoc}
526          */
527         @Override
528         public <E2> E2 getQuery() {
529                 return (E2)this.traversal;
530         }
531         
532         /**
533          * @{inheritDoc}
534          */
535         @Override
536         public QueryBuilder<E> getParentQuery() {
537
538                 return cloneQueryAtStep(parentStepIndex);
539         }
540         
541         @Override
542         public QueryBuilder<E> getContainerQuery() {
543                 
544                 if (this.parentStepIndex == 0) {
545                         return removeQueryStepsBetween(0, containerStepIndex);
546                 } else {
547                         return cloneQueryAtStep(containerStepIndex);
548                 }
549         }
550         
551         /**
552          * @{inheritDoc}
553          */
554         @Override
555         public void markParentBoundary() {
556                 parentStepIndex = stepIndex;
557         }
558         
559         @Override
560         public void markContainer() {
561                 containerStepIndex = stepIndex;
562         }
563         
564         
565         /**
566          * @{inheritDoc}
567          */
568         @Override
569         public Vertex getStart() {
570                 return this.start;
571         }
572
573         protected int getParentStepIndex() {
574                 return parentStepIndex;
575         }
576
577         protected int getContainerStepIndex() {
578                 return containerStepIndex;
579         }
580
581         protected int getStepIndex() {
582                 return stepIndex;
583         }
584
585         protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
586         /**
587          * end is exclusive
588          * 
589          * @param start
590          * @param end
591          * @return
592          */
593         protected abstract QueryBuilder<E> removeQueryStepsBetween(int start, int end);
594         
595         private void executeQuery() {
596                 
597                 Admin<Vertex, Vertex> admin;
598                 if (start != null) {
599                         admin = source.V(start).asAdmin();
600                 } else {
601                         admin = source.V().asAdmin();
602
603                 }
604                 
605                 TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin);
606                 
607                 this.completeTraversal = (Admin<Vertex, E>) admin;
608         }
609         
610         @Override
611         public boolean hasNext() {
612                 if (this.completeTraversal == null) {
613                         executeQuery();
614                 }
615                 
616                 return this.completeTraversal.hasNext();
617         }
618         
619         @Override
620         public E next() {
621                 if (this.completeTraversal == null) {
622                         executeQuery();
623                 }
624                 
625                 return this.completeTraversal.next();
626         }
627         
628         @Override
629         public List<E> toList() {
630                 if (this.completeTraversal == null) {
631                         executeQuery();
632                 }
633                 
634                 return this.completeTraversal.toList();
635         }
636
637 }