import org.onap.aai.exceptions.AAIException;
import org.onap.aai.introspection.Version;
import org.onap.aai.serialization.db.exceptions.EdgeMultiplicityException;
+import org.onap.aai.serialization.db.exceptions.MultipleEdgeRuleFoundException;
import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
import com.att.eelf.configuration.EELFLogger;
public class EdgeRules {
+ private static final String LABEL = "label";
+
+ private static final String NOT_DIRECTION_NOTATION = "!${direction}";
+
+ private static final String DIRECTION_NOTATION = "${direction}";
+
private EELFLogger logger = EELFManager.getInstance().getLogger(EdgeRules.class);
private DocumentContext rulesDoc;
rulesDoc = JsonPath.parse(json);
}
- private String getEdgeRuleJson(String rulesFilename) {
- InputStream is = getClass().getResourceAsStream(rulesFilename);
-
- Scanner scanner = new Scanner(is);
- String json = scanner.useDelimiter("\\Z").next();
- scanner.close();
-
- return json;
- }
-
/**
* Loads the versioned DbEdgeRules json file for later parsing.
*/
- @SuppressWarnings("unchecked")
private EdgeRules(Version version) {
String json = this.getEdgeRuleJson(version);
rulesDoc = JsonPath.parse(json);
}
-
- private String getEdgeRuleJson(Version version) {
- InputStream is = getClass().getResourceAsStream("/dbedgerules/DbEdgeRules_" + version.toString() + ".json");
- Scanner scanner = new Scanner(is);
- String json = scanner.useDelimiter("\\Z").next();
- scanner.close();
-
- return json;
- }
-
- private static class Helper {
- private static final EdgeRules INSTANCE = new EdgeRules();
- private static final Map<Version, EdgeRules> INSTANCEMAP = new ConcurrentHashMap<>();
-
- private static EdgeRules getEdgeRulesByFilename(String rulesFilename) {
- return new EdgeRules(rulesFilename);
- }
-
- private static EdgeRules getVersionedEdgeRules(Version v) {
- if (Version.isLatest(v)) {
- return INSTANCE;
- }
- if (!INSTANCEMAP.containsKey(v)) {
- INSTANCEMAP.put(v, new EdgeRules(v));
- }
- return INSTANCEMAP.get(v);
- }
- }
-
/**
* Gets the single instance of EdgeRules.
*
public static EdgeRules getInstance(String rulesFilename) {
return Helper.getEdgeRulesByFilename(rulesFilename);
}
+
+ private String getEdgeRuleJson(String rulesFilename) {
+ InputStream is = getClass().getResourceAsStream(rulesFilename);
+ Scanner scanner = new Scanner(is);
+ String json = scanner.useDelimiter("\\Z").next();
+ scanner.close();
+
+ return json;
+ }
+
+ private String getEdgeRuleJson(Version version) {
+ return this.getEdgeRuleJson("/dbedgerules/DbEdgeRules_" + version.toString() + ".json");
+ }
+
/**
* Adds the tree edge.
*
* @throws AAIException the AAI exception
*/
public Edge addTreeEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
- return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex, false);
+ return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex, false, null);
}
-
+
/**
* Adds the edge.
*
* @throws AAIException the AAI exception
*/
public Edge addEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
- return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex, false);
+ return this.addEdge(traversalSource, aVertex, bVertex, null);
}
-
+
+ public Edge addEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
+ return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex, false, label);
+ }
+
/**
* Adds the tree edge.
*
* @throws AAIException the AAI exception
*/
public Edge addTreeEdgeIfPossible(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
- return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex, true);
+ return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex, true, null);
}
-
+
/**
* Adds the edge.
*
* @throws AAIException the AAI exception
*/
public Edge addEdgeIfPossible(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
- return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex, true);
+ return this.addEdgeIfPossible(traversalSource, aVertex, bVertex, null);
}
+ public Edge addEdgeIfPossible(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
+ return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex, true, label);
+ }
+
/**
* Adds the edge.
*
* @return the edge
* @throws AAIException the AAI exception
*/
- private Edge addEdge(EdgeType type, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex, boolean isBestEffort) throws AAIException {
+ private Edge addEdge(EdgeType type, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex, boolean isBestEffort, String label) throws AAIException {
- EdgeRule rule = this.getEdgeRule(type, aVertex, bVertex);
+ EdgeRule rule = this.getEdgeRule(type, aVertex, bVertex, label);
Edge e = null;
-
+
Optional<String> message = this.validateMultiplicity(rule, traversalSource, aVertex, bVertex);
-
+
if (message.isPresent() && !isBestEffort) {
throw new EdgeMultiplicityException(message.get());
}
} else if (rule.getDirection().equals(Direction.IN)) {
e = bVertex.addEdge(rule.getLabel(), aVertex);
}
-
+
this.addProperties(e, rule);
}
return e;
}
-
+
/**
* Adds the properties.
*
* @param rule the rule
*/
public void addProperties(Edge edge, EdgeRule rule) {
-
+
// In DbEdgeRules.EdgeRules -- What we have as "edgeRule" is a comma-delimited set of strings.
// The first item is the edgeLabel.
// The second in the list is always "direction" which is always OUT for the way we've implemented it.
- // Items starting at "firstTagIndex" and up are all assumed to be booleans that map according to
+ // Items starting at "firstTagIndex" and up are all assumed to be booleans that map according to
// tags as defined in EdgeInfoMap.
// Note - if they are tagged as 'reverse', that means they get the tag name with "-REV" on it
Map<EdgeProperty, String> propMap = rule.getEdgeProperties();
-
+
for (Entry<EdgeProperty, String> entry : propMap.entrySet()) {
edge.property(entry.getKey().toString(), entry.getValue());
}
}
-
+
/**
- * Checks if any edge rules exist between the two given nodes, in either A|B or B|A order.
+ * Checks if any edge rules exist between the two given node types, in either A|B or B|A order.
*
* @param nodeA - node at one end of the edge
* @param nodeB - node at the other end
* @return true, if any such rules exist
*/
public boolean hasEdgeRule(String nodeA, String nodeB) {
- Filter aToB = filter(
- where("from").is(nodeA).and("to").is(nodeB)
- );
- Filter bToA = filter(
- where("from").is(nodeB).and("to").is(nodeA)
- );
-
- List<Map<String, String>> results = readRules(aToB);
- results.addAll(readRules(bToA));
+ return this.hasEdgeRule(nodeA, nodeB, null);
+ }
+
+ /**
+ * Checks if any edge rules exist between the two given node types with contains-other-v !NONE, in either A|B or B|A order.
+ *
+ * @param nodeA - node at one end of the edge
+ * @param nodeB - node at the other end
+ * @return true, if any such rules exist
+ */
+ public boolean hasTreeEdgeRule(String nodeA, String nodeB) {
+ return this.hasEdgeRule(EdgeType.TREE, nodeA, nodeB, null);
+ }
- return !results.isEmpty();
-
+ /**
+ * Checks if any edge rules exist between the two given node types with contains-other-v NONE, in either A|B or B|A order.
+ *
+ * @param nodeA - node at one end of the edge
+ * @param nodeB - node at the other end
+ * @param label - edge label
+ * @return true, if any such rules exist
+ */
+ public boolean hasCousinEdgeRule(String nodeA, String nodeB, String label) {
+ return this.hasEdgeRule(EdgeType.COUSIN, nodeA, nodeB, label);
+ }
+
+ /**
+ * Checks if any edge rules exist between the two given nodes with contains-other-v !NONE, in either A|B or B|A order.
+ *
+ * @param aVertex - node at one end of the edge
+ * @param bVertex - node at the other end
+ * @return true, if any such rules exist
+ */
+ public boolean hasTreeEdgeRule(Vertex aVertex, Vertex bVertex) {
+ String outType = aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ String inType = bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ return this.hasTreeEdgeRule(outType, inType);
+ }
+
+ /**
+ * Checks if any edge rules exist between the two given nodes with contains-other-v NONE with edge label, in either A|B or B|A order.
+ *
+ * @param aVertex - node at one end of the edge
+ * @param bVertex - node at the other end
+ * @param label - edge label
+ * @return true, if any such rules exist
+ */
+ public boolean hasCousinEdgeRule(Vertex aVertex, Vertex bVertex, String label) {
+ String outType = aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ String inType = bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ return this.hasCousinEdgeRule(outType, inType, label);
+ }
+
+ /**
+ * Checks if any edge rules exist between the two given nodes w/ edge label, in either A|B or B|A order.
+ *
+ * @param nodeA - node at one end of the edge
+ * @param nodeB - node at the other end
+ * @param label - edge label
+ * @return true, if any such rules exist
+ */
+ public boolean hasEdgeRule(String nodeA, String nodeB, String label) {
+ return this.hasEdgeRule(null, nodeA, nodeB, label);
}
/**
* @return true, if any such rules exist
*/
public boolean hasEdgeRule(Vertex aVertex, Vertex bVertex) {
- String outType = aVertex.<String>property("aai-node-type").orElse(null);
- String inType = bVertex.<String>property("aai-node-type").orElse(null);
-
- return this.hasEdgeRule(outType, inType);
-
+ return this.hasEdgeRule(aVertex, bVertex, null);
+
+ }
+
+ /**
+ * Checks if any edge rules exist between the two given nodes with label, in either A|B or B|A order with edge label.
+ *
+ * @param aVertex - node at one end of the edge
+ * @param bVertex - node at the other end
+ * @param label - edge label
+ * @return true, if any such rules exist
+ */
+ public boolean hasEdgeRule(Vertex aVertex, Vertex bVertex, String label) {
+ String outType = aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ String inType = bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+
+ if (label == null) {
+ return this.hasEdgeRule(outType, inType);
+ } else {
+ return this.hasEdgeRule(outType, inType, label);
+ }
+ }
+
+ /**
+ * Checks if any edge rules exist between the two given node types, in either A|B or B|A order with edge label and edge type.
+ *
+ * @param type - type of edge EdgeType.COUSIN | EdgeType.TREE
+ * @param nodeA - node at one end of the edge
+ * @param nodeB - node at the other end
+ * @param label - edge label
+ * @return true, if any such rules exist
+ */
+ public boolean hasEdgeRule(EdgeType type, String nodeA, String nodeB, String label) {
+ Filter aToB = filter(
+ where("from").is(nodeA)
+ .and("to").is(nodeB)
+ );
+ Filter bToA = filter(
+ where("from").is(nodeB)
+ .and("to").is(nodeA)
+ );
+
+ if (EdgeType.TREE.equals(type)) {
+ aToB = aToB.and(where(EdgeProperty.CONTAINS.toString()).ne(AAIDirection.NONE.toString()));
+ bToA = bToA.and(where(EdgeProperty.CONTAINS.toString()).ne(AAIDirection.NONE.toString()));
+ } else if (EdgeType.COUSIN.equals(type)) {
+ aToB = aToB.and(where(EdgeProperty.CONTAINS.toString()).is(AAIDirection.NONE.toString()));
+ bToA = bToA.and(where(EdgeProperty.CONTAINS.toString()).is(AAIDirection.NONE.toString()));
+ }
+
+ if (label != null) {
+ aToB = aToB.and(where(LABEL).is(label));
+ bToA = bToA.and(where(LABEL).is(label));
+ }
+
+ List<Object> results = rulesDoc.read("$.rules.[?]", aToB);
+ results.addAll(rulesDoc.read("$.rules.[?]", bToA));
+
+ return !results.isEmpty();
}
/**
* The rules will be phrased in terms of out|in, though this will
* also find rules defined as in|out (it will flip the direction in
* the EdgeRule object returned accordingly to match out|in).
- *
- * @param outType
+ *
+ * @param outType
+ * @param inType
+ * @return Map<String edgeLabel, EdgeRule rule> where edgeLabel is the label name
+ * @throws AAIException
+ */
+ public Map<String, EdgeRule> getEdgeRules(String outType, String inType) {
+ return this.getEdgeRules(outType, inType, null);
+ }
+
+ /**
+ * Gets all the edge rules that exist between the given node types with given label.
+ * The rules will be phrased in terms of out|in, though this will
+ * also find rules defined as in|out (it will flip the direction in
+ * the EdgeRule object returned accordingly to match out|in).
+ *
+ * @param outType
* @param inType
+ * @param label
* @return Map<String edgeLabel, EdgeRule rule> where edgeLabel is the label name
* @throws AAIException
*/
- public Map<String, EdgeRule> getEdgeRules(String outType, String inType) throws AAIException {
- Map<String, EdgeRule> result = new HashMap<>();
- EdgeRule rule = null;
+ public Map<String, EdgeRule> getEdgeRules(String outType, String inType, String label) {
+ final Map<String, EdgeRule> result = new HashMap<>();
+
for (EdgeType type : EdgeType.values()) {
- try {
- rule = this.getEdgeRule(type, outType, inType);
- result.put(rule.getLabel(), rule);
- } catch (NoEdgeRuleFoundException e) {
- continue;
- }
+ result.putAll(this.getEdgeRules(type, outType, inType, label));
}
-
+
return result;
}
-
+ /**
+ * Looks up edge rules for the given node types and the labels specified
+ * @param type
+ * @param outType
+ * @param inType
+ * @param labels
+ * @return
+ * @throws NoEdgeRuleFoundException
+ * @throws MultipleEdgeRuleFoundException
+ */
+ public Map<String, EdgeRule> getEdgeRulesWithLabels(EdgeType type, String outType, String inType, List<String> labels) throws NoEdgeRuleFoundException, MultipleEdgeRuleFoundException {
+ final Map<String, EdgeRule> result = new HashMap<>();
+
+ if (labels == null || labels.isEmpty()) {
+ throw new NoEdgeRuleFoundException("No labels specified");
+ }
+ for (String label : labels) {
+ EdgeRule er = this.getEdgeRule(type, outType, inType, label);
+ result.put(er.getLabel(), er);
+ }
+
+ return result;
+ }
+ /**
+ * Gets all the edge rules of that edge type that exist between the given node types with given label.
+ * The rules will be phrased in terms of out|in, though this will
+ * also find rules defined as in|out (it will flip the direction in
+ * the EdgeRule object returned accordingly to match out|in).
+ *
+ * @param type
+ * @param outType
+ * @param inType
+ * @param label
+ * @return
+ * @throws AAIException
+ */
+ public Map<String, EdgeRule> getEdgeRules(EdgeType type, String outType, String inType, String label) {
+ final Map<String, EdgeRule> result = new HashMap<>();
+
+ this.getEdgeRulesFromJson(type, outType, inType, label).forEach(edgeRuleJson -> {
+ EdgeRule edgeRule = this.buildRule(edgeRuleJson);
+ result.put(edgeRule.getLabel(), edgeRule);
+ });
+ this.getEdgeRulesFromJson(type, inType, outType, label).forEach(erj -> {
+ EdgeRule edgeRule = this.flipDirection(this.buildRule(erj));
+ if (!result.containsKey(edgeRule.getLabel())) {
+ result.put(edgeRule.getLabel(), edgeRule);
+ }
+ });
+
+
+ return result;
+ }
+
+ /**
+ * Gets all the edge rules of that edge type that exist between the given node types.
+ * The rules will be phrased in terms of out|in, though this will
+ * also find rules defined as in|out (it will flip the direction in
+ * the EdgeRule object returned accordingly to match out|in).
+ *
+ * @param type
+ * @param outType
+ * @param inType
+ * @return
+ * @throws AAIException
+ */
+ public Map<String, EdgeRule> getEdgeRules(EdgeType type, String outType, String inType) {
+ return this.getEdgeRules(type, outType, inType, null);
+ }
+
/**
* Gets the edge rule of the given type that exists between A and B.
* Will check B|A as well, and flips the direction accordingly if that succeeds
* @throws AAIException if no such edge exists
*/
public EdgeRule getEdgeRule(EdgeType type, String nodeA, String nodeB) throws AAIException {
- //try A to B
- List<Map<String, String>> aToBEdges = readRules(buildFilter(type, nodeA, nodeB));
- if (!aToBEdges.isEmpty()) {
- //lazily stop iterating if we find a match
- //should there be a mismatch between type and isParent,
- //the caller will receive something.
- //this operates on the assumption that there are at most two rules
- //for a given vertex pair
- verifyRule(aToBEdges.get(0));
- return buildRule(aToBEdges.get(0));
- }
-
- //we get here if there was nothing for A to B, so let's try B to A
- List<Map<String, String>> bToAEdges = readRules(buildFilter(type, nodeB, nodeA));
- if (!bToAEdges.isEmpty()) {
- verifyRule(bToAEdges.get(0));
- return flipDirection(buildRule(bToAEdges.get(0))); //bc we need to return as A|B, so flip the direction to match
+ return this.getEdgeRule(type, nodeA, nodeB, null);
+ }
+
+ /**
+ * Gets the edge rule of the given type that exists between A and B with edge label.
+ * Will check B|A as well, and flips the direction accordingly if that succeeds
+ * to match the expected A|B return.
+ *
+ * @param type - the type of edge you're looking for
+ * @param nodeA - first node type
+ * @param nodeB - second node type
+ * @param label - edge label
+ * @return EdgeRule describing the rule in terms of A|B, if there is any such rule
+ * @throws MultipleEdgeRuleFoundException
+ * @throws AAIException if no such edge exists
+ */
+ public EdgeRule getEdgeRule(EdgeType type, String nodeA, String nodeB, String label) throws NoEdgeRuleFoundException, MultipleEdgeRuleFoundException {
+
+ final StringBuilder errorMsg = new StringBuilder();
+ errorMsg.append(type.toString())
+ .append(" edge rule between ")
+ .append(nodeA).append(" and ").append(nodeB);
+ if (label != null) {
+ errorMsg.append(" with label ").append(label);
}
-
+
+ EdgeRule edgeRule;
+ Map<String, EdgeRule> edgeRules = this.getEdgeRules(type, nodeA, nodeB, label);
+
//found none
- throw new NoEdgeRuleFoundException("no " + type.toString() + " edge between " + nodeA + " and " + nodeB);
+ if (edgeRules.isEmpty()) {
+
+ throw new NoEdgeRuleFoundException("no " + errorMsg);
+
+ } else if (edgeRules.size() == 1) {
+
+ edgeRule = edgeRules.values().iterator().next();
+
+ } else {
+
+ Optional<EdgeRule> optionalEdgeRule = Optional.empty();
+
+ try {
+ optionalEdgeRule = this.getDefaultEdgeRule(edgeRules);
+ } catch (MultipleEdgeRuleFoundException e) {
+ throw new MultipleEdgeRuleFoundException("multiple default edge rule exists " + errorMsg);
+ }
+
+ edgeRule = optionalEdgeRule.orElseThrow(() -> new MultipleEdgeRuleFoundException("multiple edge rule exists with no default " + errorMsg));
+
+ }
+
+ return edgeRule;
}
-
+
+ private Optional<EdgeRule> getDefaultEdgeRule(Map<String, EdgeRule> edgeRules) throws MultipleEdgeRuleFoundException {
+
+ EdgeRule edgeRule = null;
+ int numDefaults = 0;
+
+ for (Map.Entry<String, EdgeRule> entry : edgeRules.entrySet()) {
+ if (entry.getValue().isDefault()) {
+ edgeRule = entry.getValue();
+ numDefaults++;
+ }
+ }
+
+ if (numDefaults > 1) {
+ throw new MultipleEdgeRuleFoundException("");
+ }
+
+ if (edgeRule == null) {
+ return Optional.empty();
+ } else {
+ return Optional.of(edgeRule);
+ }
+ }
+
+ /**
+ * Gets the rules from the edge rules Json
+ *
+ * @param type - type
+ * @param nodeA - start node
+ * @param nodeB - end node
+ * @param label - edge label to filter on
+ * @return
+ */
+ private List<Map<String, String>> getEdgeRulesFromJson(EdgeType type, String nodeA, String nodeB, String label) {
+ if (label == null) {
+ return rulesDoc.read("$.rules.[?]", buildFilter(type, nodeA, nodeB));
+ } else {
+ return rulesDoc.read("$.rules.[?]", buildFilter(type, nodeA, nodeB, label));
+ }
+ }
+
/**
* Builds a JsonPath filter to search for an edge from nodeA to nodeB with the given edge type (cousin or parent/child)
- *
+ *
* @param type
* @param nodeA - start node
* @param nodeB - end node
* @return
*/
private Filter buildFilter(EdgeType type, String nodeA, String nodeB) {
+ return this.buildFilter(type, nodeA, nodeB, null);
+ }
+
+ private Filter buildFilter(EdgeType type, String nodeA, String nodeB, String label) {
if (EdgeType.COUSIN.equals(type)) {
- return filter(
- where("from").is(nodeA).and("to").is(nodeB).and(EdgeProperty.CONTAINS.toString()).is(AAIDirection.NONE.toString())
+ Filter f = filter(
+ where("from").is(nodeA)
+ .and("to").is(nodeB)
+ .and(EdgeProperty.CONTAINS.toString()).is(AAIDirection.NONE.toString())
);
+ if (label != null) {
+ f = f.and(where(LABEL).is(label));
+ }
+
+ return f;
} else {
return filter(
- where("from").is(nodeA).and("to").is(nodeB).and(EdgeProperty.CONTAINS.toString()).is("${direction}")).or(
- where("from").is(nodeA).and("to").is(nodeB).and(EdgeProperty.CONTAINS.toString()).is("!${direction}")
+ where("from").is(nodeA).and("to").is(nodeB).and(EdgeProperty.CONTAINS.toString()).is(DIRECTION_NOTATION)).or(
+ where("from").is(nodeA).and("to").is(nodeB).and(EdgeProperty.CONTAINS.toString()).is(NOT_DIRECTION_NOTATION)
);
}
}
-
+
/**
- * Puts the give edge rule information into an EdgeRule object.
- *
- * @param edge - the edge information returned from JsonPath
+ * Puts the give edge rule information into an EdgeRule object.
+ *
+ * @param map edge rule property map
* @return EdgeRule containing that information
*/
private EdgeRule buildRule(Map<String, String> map) {
Map<String, String> edge = new EdgePropertyMap<>();
edge.putAll(map);
-
+
EdgeRule rule = new EdgeRule();
- rule.setLabel(edge.get("label"));
+ rule.setLabel(edge.get(LABEL));
rule.setDirection(edge.get("direction"));
rule.setMultiplicityRule(edge.get("multiplicity"));
rule.setContains(edge.get(EdgeProperty.CONTAINS.toString()));
rule.setDeleteOtherV(edge.get(EdgeProperty.DELETE_OTHER_V.toString()));
rule.setServiceInfrastructure(edge.get(EdgeProperty.SVC_INFRA.toString()));
rule.setPreventDelete(edge.get(EdgeProperty.PREVENT_DELETE.toString()));
-
+ if (edge.containsKey("default")) {
+ rule.setIsDefault(edge.get("default"));
+ }
+
return rule;
}
* If getEdgeRule gets a request for A|B, and it finds something as B|A, the caller still expects
* the returned EdgeRule to reflect A|B directionality. This helper method flips B|A direction to
* match this expectation.
- *
+ *
* @param rule whose direction needs flipped
* @return the updated rule
*/
rule.setDirection(Direction.IN);
return rule;
} else { //direction is BOTH, flipping both is still both
- return rule;
+ return rule;
}
}
* @throws AAIException if no such edge exists
*/
public EdgeRule getEdgeRule(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException {
+ return this.getEdgeRule(type, aVertex, bVertex, null);
+ }
+
+ /**
+ * Gets the edge rule of the given type that exists between A and B with label.
+ * Will check B|A as well, and flips the direction accordingly if that succeeds
+ * to match the expected A|B return.
+ *
+ * @param type - the type of edge you're looking for
+ * @param aVertex - first node type
+ * @param bVertex - second node type
+ * @param label - edge label
+ * @return EdgeRule describing the rule in terms of A|B, if there is any such rule
+ * @throws AAIException if no such edge exists
+ */
+ public EdgeRule getEdgeRule(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
String outType = aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
String inType = bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
-
- return this.getEdgeRule(type, outType, inType);
-
+ return this.getEdgeRule(type, outType, inType, label);
+
+
}
-
+
/**
* Validate multiplicity.
*
*/
private Optional<String> validateMultiplicity(EdgeRule rule, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) {
+ Vertex a = aVertex;
+ Vertex b = bVertex;
+
if (rule.getDirection().equals(Direction.OUT)) {
-
+ a = aVertex;
+ b = bVertex;
} else if (rule.getDirection().equals(Direction.IN)) {
- Vertex tempV = bVertex;
- bVertex = aVertex;
- aVertex = tempV;
+ a = bVertex;
+ b = aVertex;
}
-
- String aVertexType = aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
- String bVertexType = bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+
+ String aVertexType = a.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ String bVertexType = b.<String>property(AAIProperties.NODE_TYPE).orElse(null);
String label = rule.getLabel();
MultiplicityRule multiplicityRule = rule.getMultiplicityRule();
- List<Edge> outEdges = traversalSource.V(aVertex).outE(label).where(__.inV().has(AAIProperties.NODE_TYPE, bVertexType)).toList();
- List<Edge> inEdges = traversalSource.V(bVertex).inE(label).where(__.outV().has(AAIProperties.NODE_TYPE, aVertexType)).toList();
+ List<Edge> outEdges = traversalSource.V(a).outE(label).where(__.inV().has(AAIProperties.NODE_TYPE, bVertexType)).toList();
+ List<Edge> inEdges = traversalSource.V(b).inE(label).where(__.outV().has(AAIProperties.NODE_TYPE, aVertexType)).toList();
String detail = "";
+ final String msg = "multiplicity rule violated: only one edge can exist with label: ";
if (multiplicityRule.equals(MultiplicityRule.ONE2ONE)) {
- if (inEdges.size() >= 1 || outEdges.size() >= 1 ) {
- detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType;
+ if (!inEdges.isEmpty() || !outEdges.isEmpty() ) {
+ detail = msg + label + " between " + aVertexType + " and " + bVertexType;
}
} else if (multiplicityRule.equals(MultiplicityRule.ONE2MANY)) {
- if (inEdges.size() >= 1) {
- detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType;
+ if (!inEdges.isEmpty()) {
+ detail = msg + label + " between " + aVertexType + " and " + bVertexType;
}
} else if (multiplicityRule.equals(MultiplicityRule.MANY2ONE)) {
- if (outEdges.size() >= 1) {
- detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType;
+ if (!outEdges.isEmpty()) {
+ detail = msg + label + " between " + aVertexType + " and " + bVertexType;
}
- } else {
-
}
-
+
if (!"".equals(detail)) {
return Optional.of(detail);
} else {
return Optional.empty();
}
-
-
+
+
}
/**
}
}
}
-
+
/**
* Reads all the edge rules from the loaded json file.
*
/**
* Gets all the edge rules we define.
- *
+ *
* @return Multimap<String "from|to", EdgeRule rule>
*/
public Multimap<String, EdgeRule> getAllRules() {
Multimap<String, EdgeRule> result = ArrayListMultimap.create();
-
+
List<Map<String, String>> rules = readRules();
for (Map<String, String> rule : rules) {
EdgeRule er = buildRule(rule);
String name = rule.get("from") + "|" + rule.get("to");
result.put(name, er);
}
-
+
return result;
}
-
+
/**
* Gets all edge rules that define a child relationship from
* the given node type.
* @return
*/
public Set<EdgeRule> getChildren(String nodeType) {
-
+
final Filter filter = filter(
- where("from").is(nodeType).and(EdgeProperty.CONTAINS.toString()).is("${direction}")
- ).or(where("to").is(nodeType).and(EdgeProperty.CONTAINS.toString()).is("!${direction}"));
-
+ where("from").is(nodeType).and(EdgeProperty.CONTAINS.toString()).is(DIRECTION_NOTATION)
+ ).or(where("to").is(nodeType).and(EdgeProperty.CONTAINS.toString()).is(NOT_DIRECTION_NOTATION));
+
final List<Map<String, String>> rules = readRules(filter);
final Set<EdgeRule> result = new HashSet<>();
rules.forEach(item -> {
verifyRule(item);
result.add(buildRule(item));
});
-
+
return result;
-
+
+ }
+
+ private static class Helper {
+ private static final EdgeRules INSTANCE = new EdgeRules();
+ private static final Map<Version, EdgeRules> INSTANCEMAP = new ConcurrentHashMap<>();
+
+ private Helper() {}
+
+ private static EdgeRules getEdgeRulesByFilename(String rulesFilename) {
+ return new EdgeRules(rulesFilename);
+ }
+
+ private static EdgeRules getVersionedEdgeRules(Version v) {
+ if (Version.isLatest(v)) {
+ return INSTANCE;
+ }
+ if (!INSTANCEMAP.containsKey(v)) {
+ INSTANCEMAP.put(v, new EdgeRules(v));
+ }
+ return INSTANCEMAP.get(v);
+ }
}
}