X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=aai-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fonap%2Faai%2Fserialization%2Fdb%2FEdgeRules.java;h=349f9e6bf14d6bb97f29d1f0e0c25c047405fa58;hb=2e4f21dea97049f4de34fcfd789f461882e24602;hp=d9dfa457c33c106dd7bbc917dea4449212ab6f77;hpb=8dcb9900cae95a17ca6d029a665d512b3e7b11a2;p=aai%2Faai-common.git diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeRules.java b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeRules.java index d9dfa457..349f9e6b 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeRules.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeRules.java @@ -44,6 +44,7 @@ import org.onap.aai.db.props.AAIProperties; 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; @@ -56,6 +57,12 @@ import com.jayway.jsonpath.JsonPath; 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; @@ -77,54 +84,14 @@ public class EdgeRules { 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 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. * @@ -154,7 +121,21 @@ public class 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. * @@ -164,9 +145,9 @@ public class EdgeRules { * @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. * @@ -176,9 +157,13 @@ public class EdgeRules { * @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. * @@ -188,9 +173,9 @@ public class EdgeRules { * @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. * @@ -200,9 +185,13 @@ public class EdgeRules { * @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. * @@ -212,14 +201,14 @@ public class EdgeRules { * @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 message = this.validateMultiplicity(rule, traversalSource, aVertex, bVertex); - + if (message.isPresent() && !isBestEffort) { throw new EdgeMultiplicityException(message.get()); } @@ -229,12 +218,12 @@ public class EdgeRules { } else if (rule.getDirection().equals(Direction.IN)) { e = bVertex.addEdge(rule.getLabel(), aVertex); } - + this.addProperties(e, rule); } return e; } - + /** * Adds the properties. * @@ -242,40 +231,91 @@ public class EdgeRules { * @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 propMap = rule.getEdgeProperties(); - + for (Entry 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> 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.property(AAIProperties.NODE_TYPE).orElse(null); + String inType = bVertex.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.property(AAIProperties.NODE_TYPE).orElse(null); + String inType = bVertex.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); } /** @@ -286,11 +326,65 @@ public class EdgeRules { * @return true, if any such rules exist */ public boolean hasEdgeRule(Vertex aVertex, Vertex bVertex) { - String outType = aVertex.property("aai-node-type").orElse(null); - String inType = bVertex.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.property(AAIProperties.NODE_TYPE).orElse(null); + String inType = bVertex.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 results = rulesDoc.read("$.rules.[?]", aToB); + results.addAll(rulesDoc.read("$.rules.[?]", bToA)); + + return !results.isEmpty(); } /** @@ -298,29 +392,109 @@ public class EdgeRules { * 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 where edgeLabel is the label name + * @throws AAIException + */ + public Map 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 where edgeLabel is the label name * @throws AAIException */ - public Map getEdgeRules(String outType, String inType) throws AAIException { - Map result = new HashMap<>(); - EdgeRule rule = null; + public Map getEdgeRules(String outType, String inType, String label) { + final Map 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 getEdgeRulesWithLabels(EdgeType type, String outType, String inType, List labels) throws NoEdgeRuleFoundException, MultipleEdgeRuleFoundException { + final Map 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 getEdgeRules(EdgeType type, String outType, String inType, String label) { + final Map 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 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 @@ -333,69 +507,155 @@ public class EdgeRules { * @throws AAIException if no such edge exists */ public EdgeRule getEdgeRule(EdgeType type, String nodeA, String nodeB) throws AAIException { - //try A to B - List> 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> 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 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 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 getDefaultEdgeRule(Map edgeRules) throws MultipleEdgeRuleFoundException { + + EdgeRule edgeRule = null; + int numDefaults = 0; + + for (Map.Entry 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> 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 map) { Map 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; } @@ -403,7 +663,7 @@ public class EdgeRules { * 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 */ @@ -415,7 +675,7 @@ public class EdgeRules { rule.setDirection(Direction.IN); return rule; } else { //direction is BOTH, flipping both is still both - return rule; + return rule; } } @@ -431,14 +691,30 @@ public class EdgeRules { * @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.property(AAIProperties.NODE_TYPE).orElse(null); String inType = bVertex.property(AAIProperties.NODE_TYPE).orElse(null); - - return this.getEdgeRule(type, outType, inType); - + return this.getEdgeRule(type, outType, inType, label); + + } - + /** * Validate multiplicity. * @@ -450,44 +726,46 @@ public class EdgeRules { */ private Optional 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.property(AAIProperties.NODE_TYPE).orElse(null); - String bVertexType = bVertex.property(AAIProperties.NODE_TYPE).orElse(null); + + String aVertexType = a.property(AAIProperties.NODE_TYPE).orElse(null); + String bVertexType = b.property(AAIProperties.NODE_TYPE).orElse(null); String label = rule.getLabel(); MultiplicityRule multiplicityRule = rule.getMultiplicityRule(); - List outEdges = traversalSource.V(aVertex).outE(label).where(__.inV().has(AAIProperties.NODE_TYPE, bVertexType)).toList(); - List inEdges = traversalSource.V(bVertex).inE(label).where(__.outV().has(AAIProperties.NODE_TYPE, aVertexType)).toList(); + List outEdges = traversalSource.V(a).outE(label).where(__.inV().has(AAIProperties.NODE_TYPE, bVertexType)).toList(); + List 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(); } - - + + } /** @@ -513,7 +791,7 @@ public class EdgeRules { } } } - + /** * Reads all the edge rules from the loaded json file. * @@ -547,22 +825,22 @@ public class EdgeRules { /** * Gets all the edge rules we define. - * + * * @return Multimap */ public Multimap getAllRules() { Multimap result = ArrayListMultimap.create(); - + List> rules = readRules(); for (Map 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. @@ -571,19 +849,40 @@ public class EdgeRules { * @return */ public Set 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> rules = readRules(filter); final Set 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 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); + } } }