Reduce the number of problems in aai-common by removing unused imports
[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.lang3.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         // required
61         private String nodeA;
62
63         // optional - null will translate to any value of the param
64         private String nodeB = null;
65         private String label = null;
66         private EdgeType type = null;
67         private AAIDirection direction = null;
68         private boolean isPrivate = false;
69         private SchemaVersion version = null;
70
71         public Builder(String nodeA) {
72             this.nodeA = nodeA;
73         }
74
75         public Builder(String nodeA, String nodeB) {
76             this.nodeA = nodeA;
77             this.nodeB = nodeB;
78         }
79
80         private String getFirstNodeType() {
81             return nodeA;
82         }
83
84         public Builder fromOnly() {
85             this.nodeB = FROM_ONLY;
86             return this;
87         }
88
89         private String getSecondNodeType() {
90             return nodeB;
91         }
92
93         public Builder to(String nodeB) {
94             this.nodeB = nodeB;
95             return this;
96         }
97
98         public Builder toOnly() {
99             // Allows this to be used with single parameter constructor Builder(String nodeA)
100             if (StringUtils.isEmpty(this.nodeB) && StringUtils.isNotEmpty(this.nodeA)) {
101                 this.nodeB = this.nodeA;
102             }
103             this.nodeA = TO_ONLY;
104             return this;
105         }
106
107         public Builder label(String label) {
108             this.label = label;
109             return this;
110         }
111
112         private String getLabel() {
113             return label;
114         }
115
116         public Builder edgeType(EdgeType type) {
117             this.type = type;
118             return this;
119         }
120
121         private EdgeType getEdgeType() {
122             return type;
123         }
124
125         public Builder direction(AAIDirection direction) {
126             this.direction = direction;
127             return this;
128         }
129
130         private AAIDirection getDirection() {
131             return direction;
132         }
133
134         public Builder version(SchemaVersion version) {
135             this.version = version;
136             return this;
137         }
138
139         public Builder setPrivate(boolean isPrivate) {
140             this.isPrivate = isPrivate;
141             return this;
142         }
143
144         public boolean isPrivate() {
145             return isPrivate;
146         }
147
148         private Optional<SchemaVersion> getSchemaVersion() {
149             return Optional.ofNullable(version);
150         }
151
152         public EdgeRuleQuery build() {
153             return new EdgeRuleQuery(this);
154         }
155     }
156
157     private EdgeRuleQuery(Builder builder) {
158         this.v = builder.getSchemaVersion();
159         this.nodeA = builder.getFirstNodeType();
160         this.nodeB = builder.getSecondNodeType();
161         this.label = builder.getLabel();
162         this.type = builder.getEdgeType();
163         this.direction = builder.getDirection();
164         this.isPrivate = builder.isPrivate();
165
166         // will cover from A to B case
167         List<Predicate> criteriaFromTo = new ArrayList<>();
168         // Special logic to allow for A to B case only
169         if ((FROM_ONLY).equals(builder.getSecondNodeType())) {
170             criteriaFromTo.add(buildToFromPart(builder.getFirstNodeType(), null));
171         } else {
172             criteriaFromTo.add(buildToFromPart(builder.getFirstNodeType(), builder.getSecondNodeType()));
173         }
174         // will cover from B to A case - must be separate bc jsonpath won't let me OR predicates >:C
175         List<Predicate> criteriaToFrom = new ArrayList<>();
176         // Special logic to allow for B to A case only
177         if ((TO_ONLY).equals(builder.getFirstNodeType())) {
178             criteriaToFrom.add(buildToFromPart(null, builder.getSecondNodeType()));
179         } else {
180             criteriaToFrom.add(buildToFromPart(builder.getSecondNodeType(), builder.getFirstNodeType()));
181         }
182         if (builder.getLabel() != null) {
183             Predicate labelPred = addLabel(builder.getLabel());
184             criteriaFromTo.add(labelPred);
185             criteriaToFrom.add(labelPred);
186         }
187
188         if (builder.getEdgeType() != null && builder.getEdgeType() != EdgeType.ALL) {
189             Predicate typePred = addType(builder.getEdgeType());
190             criteriaFromTo.add(typePred);
191             criteriaToFrom.add(typePred);
192         }
193         Predicate privatePredicate = Criteria.where("private").is(String.valueOf(isPrivate));
194
195         if (isPrivate) {
196             criteriaFromTo.add(privatePredicate);
197             criteriaToFrom.add(privatePredicate);
198         }
199
200         if (builder.getDirection() != null) {
201             Predicate directionPred = addDirection(builder.getDirection());
202             criteriaFromTo.add(directionPred);
203             criteriaToFrom.add(directionPred);
204         }
205         if ((TO_ONLY).equals(builder.getFirstNodeType())) {
206             this.filter = Filter.filter(criteriaToFrom);
207         } else if ((FROM_ONLY).equals(builder.getSecondNodeType())) {
208             this.filter = Filter.filter(criteriaFromTo);
209         } else {
210             this.filter = Filter.filter(criteriaFromTo).or(Filter.filter(criteriaToFrom));
211         }
212     }
213
214     private Predicate buildToFromPart(String from, String to) {
215         if (from == null && to == null) { // shouldn't ever happen though
216             throw new IllegalStateException("must have at least one node defined");
217         }
218
219         Predicate p;
220
221         if (to == null) {
222             p = Criteria.where(EdgeField.FROM.toString()).is(from);
223         } else if (from == null) {
224             p = Criteria.where(EdgeField.TO.toString()).is(to);
225         } else {
226             p = Criteria.where(EdgeField.FROM.toString()).is(from).and(EdgeField.TO.toString()).is(to);
227         }
228
229         return p;
230     }
231
232     private Predicate addLabel(String label) {
233         return Criteria.where(EdgeField.LABEL.toString()).is(label);
234     }
235
236     private Predicate addType(EdgeType type) {
237         if (type == EdgeType.COUSIN) {
238             return Criteria.where(EdgeProperty.CONTAINS.toString()).is(AAIDirection.NONE.toString());
239         } else { // equals TREE
240             return Criteria.where(EdgeProperty.CONTAINS.toString()).ne(AAIDirection.NONE.toString());
241         }
242     }
243
244     private Predicate addDirection(AAIDirection direction) {
245         if (direction == AAIDirection.OUT) {
246             return Criteria.where(EdgeField.DIRECTION.toString()).in(AAIDirection.OUT.toString(),
247                     AAIDirection.BOTH.toString());
248         } else if (direction == AAIDirection.IN) {
249             return Criteria.where(EdgeField.DIRECTION.toString()).in(AAIDirection.IN.toString(),
250                     AAIDirection.BOTH.toString());
251         } else if (direction == AAIDirection.BOTH) {
252             return Criteria.where(EdgeField.DIRECTION.toString()).is(AAIDirection.BOTH.toString());
253         } else if (direction == AAIDirection.NONE) {
254             return Criteria.where(EdgeField.DIRECTION.toString()).is(AAIDirection.NONE.toString());
255         }
256         return Criteria.where(EdgeField.DIRECTION.toString()).is(AAIDirection.NONE.toString());
257     }
258
259     /**
260      * Provides the JsonPath filter for actually querying the edge rule schema files
261      *
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      *
288      * @return the Version
289      */
290     public Optional<SchemaVersion> getVersion() {
291         return this.v;
292     }
293
294     @Override
295     public String toString() {
296         StringBuilder sb = new StringBuilder();
297
298         sb.append("EdgeRuleQuery with filter params node type: ").append(nodeA);
299
300         if (nodeB != null) {
301             sb.append(", node type: ").append(nodeB);
302         }
303
304         if (label != null) {
305             sb.append(", label: ").append(label);
306         }
307
308         sb.append(", type: ");
309         if (type != null) {
310             sb.append(type.toString());
311         } else {
312             sb.append("any");
313         }
314
315         sb.append(", isPrivate: ");
316         sb.append(isPrivate);
317
318         v.ifPresent(schemaVersion -> sb.append(", for version: ").append(schemaVersion.toString()).append("."));
319         return sb.toString();
320     }
321
322     @Override
323     public boolean equals(Object o) {
324         if (this == o)
325             return true;
326         if (o == null || getClass() != o.getClass())
327             return false;
328         EdgeRuleQuery ruleQuery = (EdgeRuleQuery) o;
329         return isPrivate == ruleQuery.isPrivate && Objects.equals(v, ruleQuery.v)
330                 && Objects.equals(nodeA, ruleQuery.nodeA) && Objects.equals(nodeB, ruleQuery.nodeB)
331                 && Objects.equals(label, ruleQuery.label) && direction == ruleQuery.direction && type == ruleQuery.type;
332     }
333
334     @Override
335     public int hashCode() {
336         return v.map(schemaVersion -> Objects.hash(schemaVersion, nodeA, nodeB, label, direction, type, isPrivate))
337                 .orElseGet(() -> Objects.hash(nodeA, nodeB, label, direction, type, isPrivate));
338     }
339
340 }