Improve the performance of resoures microservice
[aai/aai-common.git] / aai-schema-ingest / src / main / java / org / onap / aai / edges / EdgeRuleQuery.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-18 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  *  Modifications Copyright © 2018 IBM.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *   http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.aai.edges;
24
25 import org.apache.commons.lang.StringUtils;
26 import org.onap.aai.edges.enums.AAIDirection;
27 import org.onap.aai.edges.enums.EdgeField;
28 import org.onap.aai.edges.enums.EdgeProperty;
29 import org.onap.aai.edges.enums.EdgeType;
30 import org.onap.aai.setup.SchemaVersion;
31
32 import com.jayway.jsonpath.Filter;
33 import com.jayway.jsonpath.Predicate;
34
35 import static com.jayway.jsonpath.Filter.filter;
36
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.Objects;
40 import java.util.Optional;
41
42 import static com.jayway.jsonpath.Criteria.where;
43
44 /**
45  * For querying the edge rules schema (not the database)
46  *
47  */
48 public class EdgeRuleQuery {
49     private Filter filter;
50     private Optional<SchemaVersion> v;
51     private String nodeA;
52     private String nodeB;
53     private String label;
54     private AAIDirection direction;
55     private EdgeType type;
56     private boolean isPrivate;
57
58     public static class Builder {
59         private static final String TO_ONLY = "ToOnly";
60
61         private static final String FROM_ONLY = "FromOnly";
62
63         //required 
64         private String nodeA;
65         
66         //optional - null will translate to any value of the param
67         private String nodeB = null; 
68         private String label = null;
69         private EdgeType type = null;
70         private AAIDirection direction = null;
71         private boolean isPrivate = false;
72         private SchemaVersion version = null;
73         
74         public Builder(String nodeA) {
75             this.nodeA = nodeA;
76         }
77         
78         public Builder(String nodeA, String nodeB) {
79             this.nodeA = nodeA;
80             this.nodeB = nodeB;
81         }
82         
83         private String getFirstNodeType() {
84             return nodeA;
85         }
86         public Builder fromOnly() {
87             this.nodeB = FROM_ONLY;
88             return this;
89         }
90         
91         private String getSecondNodeType() {
92             return nodeB;
93         }
94
95         public Builder to(String nodeB){
96             this.nodeB = nodeB;
97             return this;
98         }
99
100         public Builder toOnly() {
101             //Allows this to be used with single parameter constructor Builder(String nodeA)
102             if(StringUtils.isEmpty(this.nodeB) && StringUtils.isNotEmpty(this.nodeA) ) {
103                 this.nodeB=this.nodeA;
104             }
105             this.nodeA = TO_ONLY;
106             return this;
107         }
108         
109         public Builder label(String label) {
110             this.label = label;
111             return this;
112         }
113         
114         private String getLabel() {
115             return label;
116         }
117         
118         public Builder edgeType(EdgeType type) {
119             this.type = type;
120             return this;
121         }
122         
123         private EdgeType getEdgeType() {
124             return type;
125         }
126         
127
128         public Builder direction(AAIDirection direction) {
129             this.direction = direction;
130             return this;
131         }
132         
133         private AAIDirection getDirection() {
134             return direction;
135         }
136                 
137         public Builder version(SchemaVersion version) {
138             this.version = version;
139             return this;
140         }
141
142         public Builder setPrivate(boolean isPrivate){
143             this.isPrivate = isPrivate;
144             return this;
145         }
146
147         public boolean isPrivate(){
148             return isPrivate;
149         }
150
151         private Optional<SchemaVersion> getSchemaVersion() {
152             return Optional.ofNullable(version);
153         }
154         
155         public EdgeRuleQuery build() {
156             return new EdgeRuleQuery(this);
157         }
158     }
159     
160     private EdgeRuleQuery(Builder builder) {
161         this.v = builder.getSchemaVersion();
162         this.nodeA = builder.getFirstNodeType();
163         this.nodeB = builder.getSecondNodeType();
164         this.label = builder.getLabel();
165         this.type = builder.getEdgeType();
166         this.direction = builder.getDirection();
167         this.isPrivate = builder.isPrivate();
168         
169         //will cover from A to B case
170         List<Predicate> criteriaFromTo = new ArrayList<>();
171         //Special logic to allow for A to B case only
172         if(("FromOnly").equals(builder.getSecondNodeType())) {
173                 criteriaFromTo.add(buildToFromPart(builder.getFirstNodeType(), null));
174         } else {
175             criteriaFromTo.add(buildToFromPart(builder.getFirstNodeType(), builder.getSecondNodeType()));
176         }
177         //will cover from B to A case - must be separate bc jsonpath won't let me OR predicates >:C
178         List<Predicate> criteriaToFrom = new ArrayList<>();
179         //Special logic to allow for B to A case only
180         if(("ToOnly").equals(builder.getFirstNodeType())) {
181             criteriaToFrom.add(buildToFromPart(null, builder.getSecondNodeType()));
182         } else {
183             criteriaToFrom.add(buildToFromPart(builder.getSecondNodeType(), builder.getFirstNodeType()));
184         }
185         if (builder.getLabel() != null) {
186             Predicate labelPred = addLabel(builder.getLabel());
187             criteriaFromTo.add(labelPred);
188             criteriaToFrom.add(labelPred);
189         }
190         
191         if (builder.getEdgeType() != null) {
192             Predicate typePred = addType(builder.getEdgeType());
193             criteriaFromTo.add(typePred);
194             criteriaToFrom.add(typePred);
195         }
196         Predicate privatePredicate = where("private").is(String.valueOf(isPrivate));
197
198         if(isPrivate){
199             criteriaFromTo.add(privatePredicate);
200             criteriaToFrom.add(privatePredicate);
201         }
202         
203         if (builder.getDirection() != null) {
204             Predicate directionPred = addDirection(builder.getDirection());
205             criteriaFromTo.add(directionPred);
206             criteriaToFrom.add(directionPred);
207         }
208         if(("ToOnly").equals(builder.getFirstNodeType())) {
209             this.filter = filter(criteriaToFrom);
210         } else if(("FromOnly").equals(builder.getSecondNodeType())) {
211             this.filter = filter(criteriaFromTo);
212         } else {
213             this.filter = filter(criteriaFromTo).or(filter(criteriaToFrom));
214         }
215     }
216     
217     private Predicate buildToFromPart(String from, String to) {
218         if (from == null && to == null) { //shouldn't ever happen though
219             throw new IllegalStateException("must have at least one node defined");
220         }
221         
222         Predicate p;
223         
224         if (to == null) {
225             p = where(EdgeField.FROM.toString()).is(from);
226         } else if (from == null) {
227             p = where(EdgeField.TO.toString()).is(to);
228         } else {
229             p = where(EdgeField.FROM.toString()).is(from).and(EdgeField.TO.toString()).is(to);
230         }
231         
232         return p;
233     }
234     
235     private Predicate addLabel(String label) {
236         return where(EdgeField.LABEL.toString()).is(label);
237     }
238     
239     private Predicate addType(EdgeType type) {
240         if (type == EdgeType.COUSIN) {
241             return where(EdgeProperty.CONTAINS.toString()).is(AAIDirection.NONE.toString());
242         } else { //equals TREE
243             return where(EdgeProperty.CONTAINS.toString()).ne(AAIDirection.NONE.toString());
244         }
245     }
246         
247     private Predicate addDirection(AAIDirection direction) {
248             if (direction == AAIDirection.OUT) {
249                 return where(EdgeField.DIRECTION.toString()).in(AAIDirection.OUT.toString(), AAIDirection.BOTH.toString());
250             } else if (direction == AAIDirection.IN) {
251                 return where(EdgeField.DIRECTION.toString()).in(AAIDirection.IN.toString(), AAIDirection.BOTH.toString());
252             } else if (direction == AAIDirection.BOTH) {
253                 return where(EdgeField.DIRECTION.toString()).is(AAIDirection.BOTH.toString());
254             } else if (direction == AAIDirection.NONE) {
255                 return where(EdgeField.DIRECTION.toString()).is(AAIDirection.NONE.toString());
256             }
257             return where(EdgeField.DIRECTION.toString()).is(AAIDirection.NONE.toString());
258     }
259     
260     /**
261      * Provides the JsonPath filter for actually querying the edge rule schema files
262      * @return Filter
263      */
264     public Filter getFilter() {
265         return this.filter;
266     }
267     
268     /**
269      * Gets the first node type given for the query.
270      * 
271      * ie, If you called Builder(A,B) this would return A,
272      * if you called Builder(B,A), it would return B,
273      * if you called Builder(A), it would return A.
274      * 
275      * This is to maintain backwards compatibility with the
276      * EdgeRules API which flipped the direction of
277      * the result EdgeRule to match the input directionality.
278      * 
279      * @return String first node type of the query
280      */
281     public String getFromType() {
282         return this.nodeA;
283     }
284     
285     /**
286      * So the Ingestor knows which version of the rules to search
287      * @return the Version
288      */
289     public Optional<SchemaVersion> getVersion() {
290         return this.v;
291     }
292     
293     @Override
294     public String toString() {
295         StringBuilder sb = new StringBuilder();
296         
297         sb.append("EdgeRuleQuery with filter params node type: ").append(nodeA);
298         
299         if (nodeB != null) {
300             sb.append(", node type: ").append(nodeB);
301         }
302         
303         if (label != null) {
304             sb.append(", label: ").append(label);
305         } 
306         
307         sb.append(", type: ");
308         if (type != null) {
309             sb.append(type.toString());
310         } else {
311             sb.append("any");
312         }
313
314         sb.append(", isPrivate: ");
315         sb.append(isPrivate);
316
317         if(v.isPresent()){
318             sb.append(", for version: ").append(v.get().toString()).append(".");
319         }
320         return sb.toString();
321     }
322
323     @Override
324     public boolean equals(Object o) {
325         if (this == o) return true;
326         if (o == null || getClass() != o.getClass()) return false;
327         EdgeRuleQuery ruleQuery = (EdgeRuleQuery) o;
328         return isPrivate == ruleQuery.isPrivate &&
329             Objects.equals(v, ruleQuery.v) &&
330             Objects.equals(nodeA, ruleQuery.nodeA) &&
331             Objects.equals(nodeB, ruleQuery.nodeB) &&
332             Objects.equals(label, ruleQuery.label) &&
333             direction == ruleQuery.direction &&
334             type == ruleQuery.type;
335     }
336
337     @Override
338     public int hashCode() {
339         if(v.isPresent()){
340             return Objects.hash(v.get(), nodeA, nodeB, label, direction, type, isPrivate);
341         } else {
342             return Objects.hash(nodeA, nodeB, label, direction, type, isPrivate);
343         }
344     }
345
346 }
347
348