2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.aai.edges;
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;
31 import com.jayway.jsonpath.Filter;
32 import com.jayway.jsonpath.Predicate;
34 import static com.jayway.jsonpath.Filter.filter;
36 import java.util.ArrayList;
37 import java.util.List;
38 import java.util.Optional;
40 import static com.jayway.jsonpath.Criteria.where;
43 * For querying the edge rules schema (not the database)
46 public class EdgeRuleQuery {
47 private Filter filter;
48 private Optional<SchemaVersion> v;
52 private AAIDirection direction;
53 private EdgeType type;
54 private boolean isPrivate;
56 public static class Builder {
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;
68 public Builder(String nodeA) {
72 public Builder(String nodeA, String nodeB) {
77 private String getFirstNodeType() {
80 public Builder fromOnly() {
81 this.nodeB = "FromOnly";
85 private String getSecondNodeType() {
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;
93 this.nodeA = "ToOnly";
97 public Builder label(String label) {
102 private String getLabel() {
106 public Builder edgeType(EdgeType type) {
111 private EdgeType getEdgeType() {
116 public Builder direction(AAIDirection direction) {
117 this.direction = direction;
121 private AAIDirection getDirection() {
125 public Builder version(SchemaVersion version) {
126 this.version = version;
130 public Builder setPrivate(boolean isPrivate){
131 this.isPrivate = isPrivate;
135 public boolean isPrivate(){
139 private Optional<SchemaVersion> getSchemaVersion() {
140 return Optional.ofNullable(version);
143 public EdgeRuleQuery build() {
144 return new EdgeRuleQuery(this);
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();
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));
163 criteriaFromTo.add(buildToFromPart(builder.getFirstNodeType(), builder.getSecondNodeType()));
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()));
171 criteriaToFrom.add(buildToFromPart(builder.getSecondNodeType(), builder.getFirstNodeType()));
173 if (builder.getLabel() != null) {
174 Predicate labelPred = addLabel(builder.getLabel());
175 criteriaFromTo.add(labelPred);
176 criteriaToFrom.add(labelPred);
179 if (builder.getEdgeType() != null) {
180 Predicate typePred = addType(builder.getEdgeType());
181 criteriaFromTo.add(typePred);
182 criteriaToFrom.add(typePred);
184 Predicate privatePredicate = where("private").is(String.valueOf(isPrivate));
187 criteriaFromTo.add(privatePredicate);
188 criteriaToFrom.add(privatePredicate);
191 if (builder.getDirection() != null) {
192 Predicate directionPred = addDirection(builder.getDirection());
193 criteriaFromTo.add(directionPred);
194 criteriaToFrom.add(directionPred);
196 if(("ToOnly").equals(builder.getFirstNodeType())) {
197 this.filter = filter(criteriaToFrom);
198 } else if(("FromOnly").equals(builder.getSecondNodeType())) {
199 this.filter = filter(criteriaFromTo);
201 this.filter = filter(criteriaFromTo).or(filter(criteriaToFrom));
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");
213 p = where(EdgeField.FROM.toString()).is(from);
214 } else if (from == null) {
215 p = where(EdgeField.TO.toString()).is(to);
217 p = where(EdgeField.FROM.toString()).is(from).and(EdgeField.TO.toString()).is(to);
223 private Predicate addLabel(String label) {
224 return where(EdgeField.LABEL.toString()).is(label);
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());
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());
245 return where(EdgeField.DIRECTION.toString()).is(AAIDirection.NONE.toString());
249 * Provides the JsonPath filter for actually querying the edge rule schema files
252 public Filter getFilter() {
257 * Gets the first node type given for the query.
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.
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.
267 * @return String first node type of the query
269 public String getFromType() {
274 * So the Ingestor knows which version of the rules to search
275 * @return the Version
277 public Optional<SchemaVersion> getVersion() {
282 public String toString() {
283 StringBuilder sb = new StringBuilder();
285 sb.append("EdgeRuleQuery with filter params node type: ").append(nodeA);
288 sb.append(", node type: ").append(nodeB);
292 sb.append(", label: ").append(label);
295 sb.append(", type: ");
297 sb.append(type.toString());
302 sb.append(", isPrivate: ");
303 sb.append(isPrivate);
306 sb.append(", for version: ").append(v.get().toString()).append(".");
308 return sb.toString();