2 * ============LICENSE_START=======================================================
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
23 package org.onap.aai.edges;
25 import com.jayway.jsonpath.Criteria;
26 import com.jayway.jsonpath.Filter;
27 import com.jayway.jsonpath.Predicate;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.Objects;
32 import java.util.Optional;
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;
42 * For querying the edge rules schema (not the database)
45 public class EdgeRuleQuery {
46 private Filter filter;
47 private Optional<SchemaVersion> v;
51 private AAIDirection direction;
52 private EdgeType type;
53 private boolean isPrivate;
55 private static final String TO_ONLY = "ToOnly";
56 private static final String FROM_ONLY = "FromOnly";
58 public static class Builder {
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;
71 public Builder(String nodeA) {
75 public Builder(String nodeA, String nodeB) {
80 private String getFirstNodeType() {
84 public Builder fromOnly() {
85 this.nodeB = FROM_ONLY;
89 private String getSecondNodeType() {
93 public Builder to(String nodeB) {
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;
103 this.nodeA = TO_ONLY;
107 public Builder label(String label) {
112 private String getLabel() {
116 public Builder edgeType(EdgeType type) {
121 private EdgeType getEdgeType() {
125 public Builder direction(AAIDirection direction) {
126 this.direction = direction;
130 private AAIDirection getDirection() {
134 public Builder version(SchemaVersion version) {
135 this.version = version;
139 public Builder setPrivate(boolean isPrivate) {
140 this.isPrivate = isPrivate;
144 public boolean isPrivate() {
148 private Optional<SchemaVersion> getSchemaVersion() {
149 return Optional.ofNullable(version);
152 public EdgeRuleQuery build() {
153 return new EdgeRuleQuery(this);
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();
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));
172 criteriaFromTo.add(buildToFromPart(builder.getFirstNodeType(), builder.getSecondNodeType()));
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()));
180 criteriaToFrom.add(buildToFromPart(builder.getSecondNodeType(), builder.getFirstNodeType()));
182 if (builder.getLabel() != null) {
183 Predicate labelPred = addLabel(builder.getLabel());
184 criteriaFromTo.add(labelPred);
185 criteriaToFrom.add(labelPred);
188 if (builder.getEdgeType() != null && builder.getEdgeType() != EdgeType.ALL) {
189 Predicate typePred = addType(builder.getEdgeType());
190 criteriaFromTo.add(typePred);
191 criteriaToFrom.add(typePred);
193 Predicate privatePredicate = Criteria.where("private").is(String.valueOf(isPrivate));
196 criteriaFromTo.add(privatePredicate);
197 criteriaToFrom.add(privatePredicate);
200 if (builder.getDirection() != null) {
201 Predicate directionPred = addDirection(builder.getDirection());
202 criteriaFromTo.add(directionPred);
203 criteriaToFrom.add(directionPred);
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);
210 this.filter = Filter.filter(criteriaFromTo).or(Filter.filter(criteriaToFrom));
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");
222 p = Criteria.where(EdgeField.FROM.toString()).is(from);
223 } else if (from == null) {
224 p = Criteria.where(EdgeField.TO.toString()).is(to);
226 p = Criteria.where(EdgeField.FROM.toString()).is(from).and(EdgeField.TO.toString()).is(to);
232 private Predicate addLabel(String label) {
233 return Criteria.where(EdgeField.LABEL.toString()).is(label);
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());
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());
256 return Criteria.where(EdgeField.DIRECTION.toString()).is(AAIDirection.NONE.toString());
260 * Provides the JsonPath filter for actually querying the edge rule schema files
264 public Filter getFilter() {
269 * Gets the first node type given for the query.
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.
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.
279 * @return String first node type of the query
281 public String getFromType() {
286 * So the Ingestor knows which version of the rules to search
288 * @return the Version
290 public Optional<SchemaVersion> getVersion() {
295 public String toString() {
296 StringBuilder sb = new StringBuilder();
298 sb.append("EdgeRuleQuery with filter params node type: ").append(nodeA);
301 sb.append(", node type: ").append(nodeB);
305 sb.append(", label: ").append(label);
308 sb.append(", type: ");
310 sb.append(type.toString());
315 sb.append(", isPrivate: ");
316 sb.append(isPrivate);
318 v.ifPresent(schemaVersion -> sb.append(", for version: ").append(schemaVersion.toString()).append("."));
319 return sb.toString();
323 public boolean equals(Object o) {
326 if (o == null || getClass() != o.getClass())
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;
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));