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