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