5801e81629b0fc0781116bf32f89029aa2bee5c4
[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.Optional;
40
41 import static com.jayway.jsonpath.Criteria.where;
42
43 /**
44  * For querying the edge rules schema (not the database)
45  *
46  */
47 public class EdgeRuleQuery {
48     private Filter filter;
49     private Optional<SchemaVersion> v;
50     private String nodeA;
51     private String nodeB;
52     private String label;
53     private AAIDirection direction;
54     private EdgeType type;
55     private boolean isPrivate;
56
57     public static class Builder {
58         private static final String TO_ONLY = "ToOnly";
59
60         private static final String FROM_ONLY = "FromOnly";
61
62         //required 
63         private String nodeA;
64         
65         //optional - null will translate to any value of the param
66         private String nodeB = null; 
67         private String label = null;
68         private EdgeType type = null;
69         private AAIDirection direction = null;
70         private boolean isPrivate = false;
71         private SchemaVersion version = null;
72         
73         public Builder(String nodeA) {
74             this.nodeA = nodeA;
75         }
76         
77         public Builder(String nodeA, String nodeB) {
78             this.nodeA = nodeA;
79             this.nodeB = nodeB;
80         }
81         
82         private String getFirstNodeType() {
83             return nodeA;
84         }
85         public Builder fromOnly() {
86             this.nodeB = FROM_ONLY;
87             return this;
88         }
89         
90         private String getSecondNodeType() {
91             return nodeB;
92         }
93         public Builder toOnly() {
94             //Allows this to be used with single parameter constructor Builder(String nodeA)
95             if(StringUtils.isEmpty(this.nodeB) && StringUtils.isNotEmpty(this.nodeA) ) {
96                 this.nodeB=this.nodeA;
97             }
98             this.nodeA = TO_ONLY;
99             return this;
100         }
101         
102         public Builder label(String label) {
103             this.label = label;
104             return this;
105         }
106         
107         private String getLabel() {
108             return label;
109         }
110         
111         public Builder edgeType(EdgeType type) {
112             this.type = type;
113             return this;
114         }
115         
116         private EdgeType getEdgeType() {
117             return type;
118         }
119         
120
121         public Builder direction(AAIDirection direction) {
122             this.direction = direction;
123             return this;
124         }
125         
126         private AAIDirection getDirection() {
127             return direction;
128         }
129                 
130         public Builder version(SchemaVersion version) {
131             this.version = version;
132             return this;
133         }
134
135         public Builder setPrivate(boolean isPrivate){
136             this.isPrivate = isPrivate;
137             return this;
138         }
139
140         public boolean isPrivate(){
141             return isPrivate;
142         }
143
144         private Optional<SchemaVersion> getSchemaVersion() {
145             return Optional.ofNullable(version);
146         }
147         
148         public EdgeRuleQuery build() {
149             return new EdgeRuleQuery(this);
150         }
151     }
152     
153     private EdgeRuleQuery(Builder builder) {
154         this.v = builder.getSchemaVersion();
155         this.nodeA = builder.getFirstNodeType();
156         this.nodeB = builder.getSecondNodeType();
157         this.label = builder.getLabel();
158         this.type = builder.getEdgeType();
159         this.direction = builder.getDirection();
160         this.isPrivate = builder.isPrivate();
161         
162         //will cover from A to B case
163         List<Predicate> criteriaFromTo = new ArrayList<>();
164         //Special logic to allow for A to B case only
165         if(("FromOnly").equals(builder.getSecondNodeType())) {
166                 criteriaFromTo.add(buildToFromPart(builder.getFirstNodeType(), null));
167         } else {
168             criteriaFromTo.add(buildToFromPart(builder.getFirstNodeType(), builder.getSecondNodeType()));
169         }
170         //will cover from B to A case - must be separate bc jsonpath won't let me OR predicates >:C
171         List<Predicate> criteriaToFrom = new ArrayList<>();
172         //Special logic to allow for B to A case only
173         if(("ToOnly").equals(builder.getFirstNodeType())) {
174             criteriaToFrom.add(buildToFromPart(null, builder.getSecondNodeType()));
175         } else {
176             criteriaToFrom.add(buildToFromPart(builder.getSecondNodeType(), builder.getFirstNodeType()));
177         }
178         if (builder.getLabel() != null) {
179             Predicate labelPred = addLabel(builder.getLabel());
180             criteriaFromTo.add(labelPred);
181             criteriaToFrom.add(labelPred);
182         }
183         
184         if (builder.getEdgeType() != null) {
185             Predicate typePred = addType(builder.getEdgeType());
186             criteriaFromTo.add(typePred);
187             criteriaToFrom.add(typePred);
188         }
189         Predicate privatePredicate = where("private").is(String.valueOf(isPrivate));
190
191         if(isPrivate){
192             criteriaFromTo.add(privatePredicate);
193             criteriaToFrom.add(privatePredicate);
194         }
195         
196         if (builder.getDirection() != null) {
197             Predicate directionPred = addDirection(builder.getDirection());
198             criteriaFromTo.add(directionPred);
199             criteriaToFrom.add(directionPred);
200         }
201         if(("ToOnly").equals(builder.getFirstNodeType())) {
202             this.filter = filter(criteriaToFrom);
203         } else if(("FromOnly").equals(builder.getSecondNodeType())) {
204             this.filter = filter(criteriaFromTo);
205         } else {
206             this.filter = filter(criteriaFromTo).or(filter(criteriaToFrom));
207         }
208     }
209     
210     private Predicate buildToFromPart(String from, String to) {
211         if (from == null && to == null) { //shouldn't ever happen though
212             throw new IllegalStateException("must have at least one node defined");
213         }
214         
215         Predicate p;
216         
217         if (to == null) {
218             p = where(EdgeField.FROM.toString()).is(from);
219         } else if (from == null) {
220             p = where(EdgeField.TO.toString()).is(to);
221         } else {
222             p = where(EdgeField.FROM.toString()).is(from).and(EdgeField.TO.toString()).is(to);
223         }
224         
225         return p;
226     }
227     
228     private Predicate addLabel(String label) {
229         return where(EdgeField.LABEL.toString()).is(label);
230     }
231     
232     private Predicate addType(EdgeType type) {
233         if (type == EdgeType.COUSIN) {
234             return where(EdgeProperty.CONTAINS.toString()).is(AAIDirection.NONE.toString());
235         } else { //equals TREE
236             return where(EdgeProperty.CONTAINS.toString()).ne(AAIDirection.NONE.toString());
237         }
238     }
239         
240     private Predicate addDirection(AAIDirection direction) {
241             if (direction == AAIDirection.OUT) {
242                 return where(EdgeField.DIRECTION.toString()).in(AAIDirection.OUT.toString(), AAIDirection.BOTH.toString());
243             } else if (direction == AAIDirection.IN) {
244                 return where(EdgeField.DIRECTION.toString()).in(AAIDirection.IN.toString(), AAIDirection.BOTH.toString());
245             } else if (direction == AAIDirection.BOTH) {
246                 return where(EdgeField.DIRECTION.toString()).is(AAIDirection.BOTH.toString());
247             } else if (direction == AAIDirection.NONE) {
248                 return where(EdgeField.DIRECTION.toString()).is(AAIDirection.NONE.toString());
249             }
250             return where(EdgeField.DIRECTION.toString()).is(AAIDirection.NONE.toString());
251     }
252     
253     /**
254      * Provides the JsonPath filter for actually querying the edge rule schema files
255      * @return Filter
256      */
257     public Filter getFilter() {
258         return this.filter;
259     }
260     
261     /**
262      * Gets the first node type given for the query.
263      * 
264      * ie, If you called Builder(A,B) this would return A,
265      * if you called Builder(B,A), it would return B,
266      * if you called Builder(A), it would return A.
267      * 
268      * This is to maintain backwards compatibility with the
269      * EdgeRules API which flipped the direction of
270      * the result EdgeRule to match the input directionality.
271      * 
272      * @return String first node type of the query
273      */
274     public String getFromType() {
275         return this.nodeA;
276     }
277     
278     /**
279      * So the Ingestor knows which version of the rules to search
280      * @return the Version
281      */
282     public Optional<SchemaVersion> getVersion() {
283         return this.v;
284     }
285     
286     @Override
287     public String toString() {
288         StringBuilder sb = new StringBuilder();
289         
290         sb.append("EdgeRuleQuery with filter params node type: ").append(nodeA);
291         
292         if (nodeB != null) {
293             sb.append(", node type: ").append(nodeB);
294         }
295         
296         if (label != null) {
297             sb.append(", label: ").append(label);
298         } 
299         
300         sb.append(", type: ");
301         if (type != null) {
302             sb.append(type.toString());
303         } else {
304             sb.append("any");
305         }
306
307         sb.append(", isPrivate: ");
308         sb.append(isPrivate);
309
310         if(v.isPresent()){
311             sb.append(", for version: ").append(v.get().toString()).append(".");
312         }
313         return sb.toString();
314     }
315 }
316
317