-/**
+/**
* ============LICENSE_START=======================================================
* org.onap.aai
* ================================================================================
- * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017-18 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Modifications Copyright © 2018 IBM.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the License for the specific language governing permissions and
* limitations under the License.
* ============LICENSE_END=========================================================
- *
- * ECOMP is a trademark and service mark of AT&T Intellectual Property.
*/
package org.onap.aai.edges;
+import org.apache.commons.lang.StringUtils;
import org.onap.aai.edges.enums.AAIDirection;
import org.onap.aai.edges.enums.EdgeField;
import org.onap.aai.edges.enums.EdgeProperty;
import org.onap.aai.edges.enums.EdgeType;
-import org.onap.aai.setup.Version;
+import org.onap.aai.setup.SchemaVersion;
import com.jayway.jsonpath.Filter;
import com.jayway.jsonpath.Predicate;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
import static com.jayway.jsonpath.Criteria.where;
*
*/
public class EdgeRuleQuery {
- private Filter filter;
- private Version v;
- private String nodeA;
- private String nodeB;
- private String label;
- private EdgeType type;
-
- public static class Builder {
- //required
- private String nodeA;
-
- //optional - null will translate to any value of the param
- private String nodeB = null;
- private String label = null;
- private EdgeType type = null;
- private Version version = Version.getLatest(); //default
-
- public Builder(String nodeA) {
- this.nodeA = nodeA;
- }
-
- public Builder(String nodeA, String nodeB) {
- this.nodeA = nodeA;
- this.nodeB = nodeB;
- }
-
- private String getFirstNodeType() {
- return nodeA;
- }
-
- private String getSecondNodeType() {
- return nodeB;
- }
-
- public Builder label(String label) {
- this.label = label;
- return this;
- }
-
- private String getLabel() {
- return label;
- }
-
- public Builder edgeType(EdgeType type) {
- this.type = type;
- return this;
- }
-
- private EdgeType getEdgeType() {
- return type;
- }
-
- public Builder version(Version version) {
- this.version = version;
- return this;
- }
- private Version getVersion() {
- return version;
- }
-
- public EdgeRuleQuery build() {
- return new EdgeRuleQuery(this);
- }
- }
-
- private EdgeRuleQuery(Builder builder) {
- this.v = builder.getVersion();
- this.nodeA = builder.getFirstNodeType();
- this.nodeB = builder.getSecondNodeType();
- this.label = builder.getLabel();
- this.type = builder.getEdgeType();
-
- //will cover from A to B case
- List<Predicate> criteriaFromTo = new ArrayList<>();
- criteriaFromTo.add(buildToFromPart(builder.getFirstNodeType(), builder.getSecondNodeType()));
- //will cover from B to A case - must be separate bc jsonpath won't let me OR predicates >:C
- List<Predicate> criteriaToFrom = new ArrayList<>();
- criteriaToFrom.add(buildToFromPart(builder.getSecondNodeType(), builder.getFirstNodeType()));
-
-
-
- if (builder.getLabel() != null) {
- Predicate labelPred = addLabel(builder.getLabel());
- criteriaFromTo.add(labelPred);
- criteriaToFrom.add(labelPred);
- }
-
- if (builder.getEdgeType() != null) {
- Predicate typePred = addType(builder.getEdgeType());
- criteriaFromTo.add(typePred);
- criteriaToFrom.add(typePred);
- }
-
-
-
- this.filter = filter(criteriaFromTo).or(filter(criteriaToFrom));
- }
-
- private Predicate buildToFromPart(String from, String to) {
- if (from == null && to == null) { //shouldn't ever happen though
- throw new IllegalStateException("must have at least one node defined");
- }
-
- Predicate p;
-
- if (to == null) {
- p = where(EdgeField.FROM.toString()).is(from);
- } else if (from == null) {
- p = where(EdgeField.TO.toString()).is(to);
- } else {
- p = where(EdgeField.FROM.toString()).is(from).and(EdgeField.TO.toString()).is(to);
- }
-
- return p;
- }
-
- private Predicate addLabel(String label) {
- return where(EdgeField.LABEL.toString()).is(label);
- }
-
- private Predicate addType(EdgeType type) {
- if (type == EdgeType.COUSIN) {
- return where(EdgeProperty.CONTAINS.toString()).is(AAIDirection.NONE.toString());
- } else { //equals TREE
- return where(EdgeProperty.CONTAINS.toString()).ne(AAIDirection.NONE.toString());
- }
- }
-
- /**
- * Provides the JsonPath filter for actually querying the edge rule schema files
- * @return Filter
- */
- public Filter getFilter() {
- return this.filter;
- }
-
- /**
- * So the Ingestor knows which version of the rules to search
- * @return the Version
- */
- public Version getVersion() {
- return this.v;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
-
- sb.append("EdgeRuleQuery with filter params node type: ").append(nodeA);
-
- if (nodeB != null) {
- sb.append(", node type: ").append(nodeB);
- }
-
- if (label != null) {
- sb.append(", label: ").append(label);
- }
-
- sb.append(", type: ");
- if (type != null) {
- sb.append(type.toString());
- } else {
- sb.append("any");
- }
-
- sb.append(", for version: ").append(v.toString()).append(".");
- return sb.toString();
- }
+ private Filter filter;
+ private Optional<SchemaVersion> v;
+ private String nodeA;
+ private String nodeB;
+ private String label;
+ private AAIDirection direction;
+ private EdgeType type;
+ private boolean isPrivate;
+
+ public static class Builder {
+ private static final String TO_ONLY = "ToOnly";
+
+ private static final String FROM_ONLY = "FromOnly";
+
+ //required
+ private String nodeA;
+
+ //optional - null will translate to any value of the param
+ private String nodeB = null;
+ private String label = null;
+ private EdgeType type = null;
+ private AAIDirection direction = null;
+ private boolean isPrivate = false;
+ private SchemaVersion version = null;
+
+ public Builder(String nodeA) {
+ this.nodeA = nodeA;
+ }
+
+ public Builder(String nodeA, String nodeB) {
+ this.nodeA = nodeA;
+ this.nodeB = nodeB;
+ }
+
+ private String getFirstNodeType() {
+ return nodeA;
+ }
+ public Builder fromOnly() {
+ this.nodeB = FROM_ONLY;
+ return this;
+ }
+
+ private String getSecondNodeType() {
+ return nodeB;
+ }
+
+ public Builder to(String nodeB){
+ this.nodeB = nodeB;
+ return this;
+ }
+
+ public Builder toOnly() {
+ //Allows this to be used with single parameter constructor Builder(String nodeA)
+ if(StringUtils.isEmpty(this.nodeB) && StringUtils.isNotEmpty(this.nodeA) ) {
+ this.nodeB=this.nodeA;
+ }
+ this.nodeA = TO_ONLY;
+ return this;
+ }
+
+ public Builder label(String label) {
+ this.label = label;
+ return this;
+ }
+
+ private String getLabel() {
+ return label;
+ }
+
+ public Builder edgeType(EdgeType type) {
+ this.type = type;
+ return this;
+ }
+
+ private EdgeType getEdgeType() {
+ return type;
+ }
+
+
+ public Builder direction(AAIDirection direction) {
+ this.direction = direction;
+ return this;
+ }
+
+ private AAIDirection getDirection() {
+ return direction;
+ }
+
+ public Builder version(SchemaVersion version) {
+ this.version = version;
+ return this;
+ }
+
+ public Builder setPrivate(boolean isPrivate){
+ this.isPrivate = isPrivate;
+ return this;
+ }
+
+ public boolean isPrivate(){
+ return isPrivate;
+ }
+
+ private Optional<SchemaVersion> getSchemaVersion() {
+ return Optional.ofNullable(version);
+ }
+
+ public EdgeRuleQuery build() {
+ return new EdgeRuleQuery(this);
+ }
+ }
+
+ private EdgeRuleQuery(Builder builder) {
+ this.v = builder.getSchemaVersion();
+ this.nodeA = builder.getFirstNodeType();
+ this.nodeB = builder.getSecondNodeType();
+ this.label = builder.getLabel();
+ this.type = builder.getEdgeType();
+ this.direction = builder.getDirection();
+ this.isPrivate = builder.isPrivate();
+
+ //will cover from A to B case
+ List<Predicate> criteriaFromTo = new ArrayList<>();
+ //Special logic to allow for A to B case only
+ if(("FromOnly").equals(builder.getSecondNodeType())) {
+ criteriaFromTo.add(buildToFromPart(builder.getFirstNodeType(), null));
+ } else {
+ criteriaFromTo.add(buildToFromPart(builder.getFirstNodeType(), builder.getSecondNodeType()));
+ }
+ //will cover from B to A case - must be separate bc jsonpath won't let me OR predicates >:C
+ List<Predicate> criteriaToFrom = new ArrayList<>();
+ //Special logic to allow for B to A case only
+ if(("ToOnly").equals(builder.getFirstNodeType())) {
+ criteriaToFrom.add(buildToFromPart(null, builder.getSecondNodeType()));
+ } else {
+ criteriaToFrom.add(buildToFromPart(builder.getSecondNodeType(), builder.getFirstNodeType()));
+ }
+ if (builder.getLabel() != null) {
+ Predicate labelPred = addLabel(builder.getLabel());
+ criteriaFromTo.add(labelPred);
+ criteriaToFrom.add(labelPred);
+ }
+
+ if (builder.getEdgeType() != null) {
+ Predicate typePred = addType(builder.getEdgeType());
+ criteriaFromTo.add(typePred);
+ criteriaToFrom.add(typePred);
+ }
+ Predicate privatePredicate = where("private").is(String.valueOf(isPrivate));
+
+ if(isPrivate){
+ criteriaFromTo.add(privatePredicate);
+ criteriaToFrom.add(privatePredicate);
+ }
+
+ if (builder.getDirection() != null) {
+ Predicate directionPred = addDirection(builder.getDirection());
+ criteriaFromTo.add(directionPred);
+ criteriaToFrom.add(directionPred);
+ }
+ if(("ToOnly").equals(builder.getFirstNodeType())) {
+ this.filter = filter(criteriaToFrom);
+ } else if(("FromOnly").equals(builder.getSecondNodeType())) {
+ this.filter = filter(criteriaFromTo);
+ } else {
+ this.filter = filter(criteriaFromTo).or(filter(criteriaToFrom));
+ }
+ }
+
+ private Predicate buildToFromPart(String from, String to) {
+ if (from == null && to == null) { //shouldn't ever happen though
+ throw new IllegalStateException("must have at least one node defined");
+ }
+
+ Predicate p;
+
+ if (to == null) {
+ p = where(EdgeField.FROM.toString()).is(from);
+ } else if (from == null) {
+ p = where(EdgeField.TO.toString()).is(to);
+ } else {
+ p = where(EdgeField.FROM.toString()).is(from).and(EdgeField.TO.toString()).is(to);
+ }
+
+ return p;
+ }
+
+ private Predicate addLabel(String label) {
+ return where(EdgeField.LABEL.toString()).is(label);
+ }
+
+ private Predicate addType(EdgeType type) {
+ if (type == EdgeType.COUSIN) {
+ return where(EdgeProperty.CONTAINS.toString()).is(AAIDirection.NONE.toString());
+ } else { //equals TREE
+ return where(EdgeProperty.CONTAINS.toString()).ne(AAIDirection.NONE.toString());
+ }
+ }
+
+ private Predicate addDirection(AAIDirection direction) {
+ if (direction == AAIDirection.OUT) {
+ return where(EdgeField.DIRECTION.toString()).in(AAIDirection.OUT.toString(), AAIDirection.BOTH.toString());
+ } else if (direction == AAIDirection.IN) {
+ return where(EdgeField.DIRECTION.toString()).in(AAIDirection.IN.toString(), AAIDirection.BOTH.toString());
+ } else if (direction == AAIDirection.BOTH) {
+ return where(EdgeField.DIRECTION.toString()).is(AAIDirection.BOTH.toString());
+ } else if (direction == AAIDirection.NONE) {
+ return where(EdgeField.DIRECTION.toString()).is(AAIDirection.NONE.toString());
+ }
+ return where(EdgeField.DIRECTION.toString()).is(AAIDirection.NONE.toString());
+ }
+
+ /**
+ * Provides the JsonPath filter for actually querying the edge rule schema files
+ * @return Filter
+ */
+ public Filter getFilter() {
+ return this.filter;
+ }
+
+ /**
+ * Gets the first node type given for the query.
+ *
+ * ie, If you called Builder(A,B) this would return A,
+ * if you called Builder(B,A), it would return B,
+ * if you called Builder(A), it would return A.
+ *
+ * This is to maintain backwards compatibility with the
+ * EdgeRules API which flipped the direction of
+ * the result EdgeRule to match the input directionality.
+ *
+ * @return String first node type of the query
+ */
+ public String getFromType() {
+ return this.nodeA;
+ }
+
+ /**
+ * So the Ingestor knows which version of the rules to search
+ * @return the Version
+ */
+ public Optional<SchemaVersion> getVersion() {
+ return this.v;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("EdgeRuleQuery with filter params node type: ").append(nodeA);
+
+ if (nodeB != null) {
+ sb.append(", node type: ").append(nodeB);
+ }
+
+ if (label != null) {
+ sb.append(", label: ").append(label);
+ }
+
+ sb.append(", type: ");
+ if (type != null) {
+ sb.append(type.toString());
+ } else {
+ sb.append("any");
+ }
+
+ sb.append(", isPrivate: ");
+ sb.append(isPrivate);
+
+ if(v.isPresent()){
+ sb.append(", for version: ").append(v.get().toString()).append(".");
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ EdgeRuleQuery ruleQuery = (EdgeRuleQuery) o;
+ return isPrivate == ruleQuery.isPrivate &&
+ Objects.equals(v, ruleQuery.v) &&
+ Objects.equals(nodeA, ruleQuery.nodeA) &&
+ Objects.equals(nodeB, ruleQuery.nodeB) &&
+ Objects.equals(label, ruleQuery.label) &&
+ direction == ruleQuery.direction &&
+ type == ruleQuery.type;
+ }
+
+ @Override
+ public int hashCode() {
+ if(v.isPresent()){
+ return Objects.hash(v.get(), nodeA, nodeB, label, direction, type, isPrivate);
+ } else {
+ return Objects.hash(nodeA, nodeB, label, direction, type, isPrivate);
+ }
+ }
+
}
+
+