From 8fb7aa6480d4d7becbbab5fcfabd6af3f57e7d74 Mon Sep 17 00:00:00 2001 From: "Kajur, Harish (vk250x)" Date: Tue, 4 Dec 2018 14:06:14 -0500 Subject: Improve the performance of resoures microservice Currently the findSubGraph is being invoked and causing additional calls to the database by backing a tree backed vertex and slowing the performance of GET ALLs Original intention of both of them was to pre fetch depth 0, 1, and 2 at once so we don't have to get them at each depth but since that was not done right there is extra amount of time After the aai-uri migration to ensure all vertexes have the aai-uri and also to make sure they are unique across graph we don't need to traverse a vertex to find the parents to build aai-uri it was done previously when there was no aai-uri to derive the uri of a given vertex and its not necessary anymore so there would be performance improvements of vserver when there are a lot of relationships Currently the edge labels are retrieved for each vertex a and b and the performance of the GET with relationships will be propotional to the GET request and how many cousin edges it has and the more cousin edges there are the more slower the response time will be as for each cousin vertex its trying to get the edge in between so the code is modified to only go to the database for the edge label when there are multiple edge labels (cousin edges) between a and b If there are only one edge label and its a cousin vertex then we can use the edge rule to be able to figure out the edge label Improve PUT on the cloud region by modifying the getEdgesBetween method which currently was retrieving all the parent child edges between a and b and then only using the first edge The traversal itself was too complicated and was costly in terms of database retrieval and calls and optimized the code to utilize the edge information so we can modify the query to db at runtime based on the information provided so when a 10000 vservers under a tenant adding a new vserver under tenant would be slow because of the old query performance as it was taking some time there but with this optimization, its only spending at most a millisecond or 2 in that method Also noticed that when a PUT operation takes place, the method calls the related objects to create a dmaap event which was in turn calling the findParents and actually utilizing the parents to create the dmaap event and would spend quite a lot of time here because of the expensive call of the findParents in this case we need those vertexes So optimized the code so based on a given vertex, we have the aai-uri and the newly added metadata uriTemplate to break the aai-uri into its parent aai-uri and grand parent aai-uri and so forth With this breakdown, we can get the list of aai-uris which are parents, grandparents and then use the aai-uri to look them up which is O(1) lookup time due to the fact they are unique indexes The time it takes when doing a traversal to find the parents is propotional to the number of edges but this will be optimistic Another area which was improved was the json path execution of the edge rules so when the edge rules get loaded into memory it creates a document object, it utilizes the jsonpath to query information about the edge rules but the only thing here is each time it gets called the query gets invoked and uses jsonpath to retrieve the edge rules when we can cached them based on the filter so that the user executed and if the filter is the same as before, the expected edge rules will return the same Too much time was spent making the query and retrieving and building the edgerules So a cache is a perfect way to optimize this part Issue-ID: AAI-1987 Change-Id: Ieb8237de3fd31136ceac14bf4a8216a7ab3b7179 Signed-off-by: Kajur, Harish (vk250x) --- .../main/java/org/onap/aai/edges/EdgeIngestor.java | 371 +++++++++++++-------- .../src/main/java/org/onap/aai/edges/EdgeRule.java | 51 ++- .../java/org/onap/aai/edges/EdgeRuleQuery.java | 33 +- .../main/java/org/onap/aai/edges/SchemaFilter.java | 69 ++++ .../exceptions/AmbiguousRuleChoiceException.java | 6 +- .../exceptions/EdgeRuleNotFoundException.java | 6 +- 6 files changed, 381 insertions(+), 155 deletions(-) create mode 100644 aai-schema-ingest/src/main/java/org/onap/aai/edges/SchemaFilter.java (limited to 'aai-schema-ingest') diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeIngestor.java b/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeIngestor.java index dfcd0db3..c2c58d5f 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeIngestor.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeIngestor.java @@ -1,4 +1,4 @@ -/** +/** * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ @@ -20,11 +20,16 @@ package org.onap.aai.edges; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import org.apache.tinkerpop.gremlin.structure.Direction; import org.onap.aai.edges.enums.DirectionNotation; import org.onap.aai.edges.enums.EdgeField; @@ -34,6 +39,8 @@ import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException; import org.onap.aai.setup.ConfigTranslator; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -51,15 +58,25 @@ import static com.jayway.jsonpath.Criteria.where; */ @Component public class EdgeIngestor { - private Map> versionJsonFilesMap; + + private static final Logger LOG = LoggerFactory.getLogger(EdgeIngestor.class); + + private Map> versionJsonFilesMap; private static final String READ_START = "$.rules.[?]"; private static final String READ_ALL_START = "$.rules.*"; private SchemaVersions schemaVersions; + + private Set multipleLabelKeys; + + private final LoadingCache> cacheFilterStore; + + private final LoadingCache cousinLabelStore; + //-----ingest-----// /** * Instantiates the EdgeIngestor bean. - * + * * @param translator - ConfigTranslator autowired in by Spring framework which * contains the configuration information needed to ingest the desired files. */ @@ -69,20 +86,41 @@ public class EdgeIngestor { JsonIngestor ji = new JsonIngestor(); this.schemaVersions = schemaVersions; versionJsonFilesMap = ji.ingest(filesToIngest); + this.cacheFilterStore = CacheBuilder.newBuilder() + .maximumSize(2000) + .build( + new CacheLoader>() { + @Override + public Multimap load(SchemaFilter key) { + return extractRules(key); + } + } + ); + + this.cousinLabelStore = CacheBuilder.newBuilder() + .maximumSize(50) + .build( + new CacheLoader() { + @Override + public String[] load(String key) throws Exception { + return retrieveCousinLabels(key); + } + } + ); } - + //-----methods for getting rule info-----// - + /** * Gets list of all edge rules defined in the latest version's schema - * + * * @return Multimap of node names keys to the EdgeRules associated with those types - * where the key takes the form of + * where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple * rules for a pair of node types but the from/to value in the json is flipped for some of them. * @throws EdgeRuleNotFoundException if none found @@ -90,17 +128,47 @@ public class EdgeIngestor { public Multimap getAllCurrentRules() throws EdgeRuleNotFoundException { return getAllRules(schemaVersions.getDefaultVersion()); } - + + /** + * Retrieves all the nodes that contain multiple edge labels + * + * A lazy instantiation to retrieve all this info on first call + * + * @return a set containing a list of strings where each string is + * concatenated by a pipe (|) character such as aNodeType|bNodeType + */ + public Set getMultipleLabelKeys(){ + + if(multipleLabelKeys == null){ + multipleLabelKeys = new HashSet<>(); + try { + final Multimap edges = this.getAllCurrentRules(); + if(edges == null || edges.isEmpty()){ + LOG.warn("Unable to find any edge rules for the latest version"); + } + edges.keySet().forEach((key) -> { + Collection rules = edges.get(key); + if(rules.size() > 1){ + multipleLabelKeys.add(key); + } + }); + } catch (EdgeRuleNotFoundException e) { + LOG.info("For the latest schema version, unable to find any edges with multiple keys"); + } + } + + return multipleLabelKeys; + } /** * Gets list of all edge rules defined in the given version's schema - * + * * @return Multimap of node names keys to the EdgeRules associated with those types - * where the key takes the form of + * where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple * rules for a pair of node types but the from/to value in the json is flipped for some of them. * @throws EdgeRuleNotFoundException if none found @@ -113,19 +181,19 @@ public class EdgeIngestor { return found; } } - + /** * Finds the rules (if any) matching the given query criteria. If none, the returned Multimap * will be empty. - * + * * @param q - EdgeRuleQuery with filter criteria set - * - * @return Multimap of node names keys to the EdgeRules where the key takes the form of + * + * @return Multimap of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple * rules for a pair of node types but the from/to value in the json is flipped for some of them. * @throws EdgeRuleNotFoundException if none found @@ -140,36 +208,40 @@ public class EdgeIngestor { if (found.isEmpty()) { throw new EdgeRuleNotFoundException("No rules found for " + q.toString()); } else { - for (EdgeRule rule : found.values()) { - if (!q.getFromType().equals(rule.getFrom())) { - /* To maintain backwards compatibility with old EdgeRules API, - * where the direction of the returned EdgeRule would be - * flipped (if necessary) to match the directionality of - * the input params. - * ie, If the rule is from=A,to=B,direction=OUT, - * if the user asked (A,B) the direction would be OUT, - * if they asked (B,A), it would be IN to match. - */ - rule.flipDirection(); - } - } - return found; + Multimap copy = ArrayListMultimap.create(); + found.entries().stream().forEach((entry) -> { + EdgeRule rule = new EdgeRule(entry.getValue()); + if(!q.getFromType().equals(rule.getFrom())){ + /* To maintain backwards compatibility with old EdgeRules API, + * where the direction of the returned EdgeRule would be + * flipped (if necessary) to match the directionality of + * the input params. + * ie, If the rule is from=A,to=B,direction=OUT, + * if the user asked (A,B) the direction would be OUT, + * if they asked (B,A), it would be IN to match. + */ + rule.flipDirection(); + } + copy.put(entry.getKey(), rule); + }); + + return copy; } } - + /** * Gets the rule satisfying the given filter criteria. If there are more than one - * that match, return the default rule. If there is no clear default to return, or + * that match, return the default rule. If there is no clear default to return, or * no rules match at all, error. - * + * * @param q - EdgeRuleQuery with filter criteria set * @return EdgeRule satisfying given criteria * @throws EdgeRuleNotFoundException if none found that match * @throws AmbiguousRuleChoiceException if multiple match but no way to choice one from them - * Specifically, if multiple node type pairs come back (ie bar|foo and asdf|foo, + * Specifically, if multiple node type pairs come back (ie bar|foo and asdf|foo, * no way to know which is appropriate over the others), * or if there is a mix of Tree and Cousin edges because again there is no way to - * know which is "defaulter" than the other. + * know which is "defaulter" than the other. * The default property only clarifies among multiple cousin edges of the same node pair, * ex: which l-interface|logical-link rule to default to. */ @@ -184,7 +256,7 @@ public class EdgeIngestor { if (found.isEmpty()) { throw new EdgeRuleNotFoundException("No rule found for " + q.toString() + "."); } - + EdgeRule rule = null; if (found.keys().size() == 1) { //only one found, cool we're done for (Entry e : found.entries()) { @@ -193,10 +265,12 @@ public class EdgeIngestor { } else { rule = getDefaultRule(found); } - + + if (rule == null) { //should never get here though throw new EdgeRuleNotFoundException("No rule found for " + q.toString() + "."); } else { + rule = new EdgeRule(rule); if (!q.getFromType().equals(rule.getFrom())) { /* To maintain backwards compatibility with old EdgeRules API, * where the direction of the returned EdgeRule would be @@ -211,7 +285,9 @@ public class EdgeIngestor { return rule; } } - + + + private EdgeRule getDefaultRule(Multimap found) throws AmbiguousRuleChoiceException { if (found.keySet().size() > 1) { //ie multiple node pairs (a|c and b|c not just all a|c) case StringBuilder sb = new StringBuilder(); @@ -220,7 +296,7 @@ public class EdgeIngestor { } throw new AmbiguousRuleChoiceException("No way to select single rule from these pairs: " + sb.toString() + "."); } - + int defaultCount = 0; EdgeRule defRule = null; for (Entry e : found.entries()) { @@ -235,13 +311,13 @@ public class EdgeIngestor { } else if (defaultCount == 0) { throw new AmbiguousRuleChoiceException("No default found."); } - + return defRule; } - + /** * Checks if there exists any rule that satisfies the given filter criteria. - * + * * @param q - EdgeRuleQuery with filter criteria set * @return boolean */ @@ -252,42 +328,59 @@ public class EdgeIngestor { return !extractRules(q.getFilter(), schemaVersions.getDefaultVersion()).isEmpty(); } } - + /** * Gets all cousin rules for the given node type in the latest schema version. - * + * * @param nodeType - * @return Multimap of node names keys to the EdgeRules where the key takes the form of + * @return Multimap of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ public Multimap getCousinRules(String nodeType) { return getCousinRules(nodeType, schemaVersions.getDefaultVersion()); //default to latest } - + + + public String[] retrieveCousinLabels(String nodeType){ + + Multimap cousinRules = getCousinRules(nodeType); + String[] cousinLabels = new String[cousinRules.size()]; + + return cousinRules.entries() + .stream() + .map((entry) -> entry.getValue().getLabel()) + .collect(Collectors.toList()) + .toArray(cousinLabels); + } + + public String[] retrieveCachedCousinLabels(String nodeType) throws ExecutionException { + return cousinLabelStore.get(nodeType); + } + /** * Gets all cousin rules for the given node type in the given schema version. - * + * * @param nodeType * @param v - the version of the edge rules to query - * @return Multimap of node names keys to the EdgeRules where the key takes the form of + * @return Multimap of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple - * rules for a pair of node types but the from/to value in the json is flipped for some of them. + * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ public Multimap getCousinRules(String nodeType, SchemaVersion v) { return extractRules(new EdgeRuleQuery.Builder(nodeType).edgeType(EdgeType.COUSIN).build().getFilter(), v); } - + /** * Returns if the given node type has any cousin relationships in the current version. * @param nodeType @@ -296,7 +389,7 @@ public class EdgeIngestor { public boolean hasCousinRule(String nodeType) { return hasCousinRule(nodeType, schemaVersions.getDefaultVersion()); } - + /** * Returns if the given node type has any cousin relationships in the given version. * @param nodeType @@ -305,45 +398,45 @@ public class EdgeIngestor { public boolean hasCousinRule(String nodeType, SchemaVersion v) { return !getCousinRules(nodeType, v).isEmpty(); } - + /** * Gets all rules where "{given nodeType} contains {otherType}" in the latest schema version. - * + * * @param nodeType - node type that is the container in the returned relationships - * @return Multimap of node names keys to the EdgeRules where the key takes the form of + * @return Multimap of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple - * rules for a pair of node types but the from/to value in the json is flipped for some of them. + * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ public Multimap getChildRules(String nodeType) { return getChildRules(nodeType, schemaVersions.getDefaultVersion()); } - + /** * Gets all rules where "{given nodeType} contains {otherType}" in the given schema version. - * + * * @param nodeType - node type that is the container in the returned relationships - * @return Multimap of node names keys to the EdgeRules where the key takes the form of + * @return Multimap of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple - * rules for a pair of node types but the from/to value in the json is flipped for some of them. + * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ public Multimap getChildRules(String nodeType, SchemaVersion v) { Filter from = assembleFilterSegments(where(EdgeField.FROM.toString()).is(nodeType), getSameDirectionContainmentCriteria()); Filter to = assembleFilterSegments(where(EdgeField.TO.toString()).is(nodeType), getOppositeDirectionContainmentCriteria()); Filter total = from.or(to); - + return extractRules(total, v); } - + /** * Returns if the given node type has any child relationships (ie it contains another node type) in the current version. * @param nodeType @@ -352,7 +445,7 @@ public class EdgeIngestor { public boolean hasChildRule(String nodeType) { return hasChildRule(nodeType, schemaVersions.getDefaultVersion()); } - + /** * Returns if the given node type has any child relationships (ie it contains another node type) in the given version. * @param nodeType @@ -361,45 +454,45 @@ public class EdgeIngestor { public boolean hasChildRule(String nodeType, SchemaVersion v) { return !getChildRules(nodeType, v).isEmpty(); } - + /** * Gets all rules where "{given nodeType} is contained by {otherType}" in the latest schema version. - * + * * @param nodeType - node type that is the containee in the returned relationships - * @return Multimap of node names keys to the EdgeRules where the key takes the form of + * @return Multimap of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ public Multimap getParentRules(String nodeType) { return getParentRules(nodeType, schemaVersions.getDefaultVersion()); } - + /** * Gets all rules where "{given nodeType} is contained by {otherType}" in the given schema version. - * + * * @param nodeType - node type that is the containee in the returned relationships - * @return Multimap of node names keys to the EdgeRules where the key takes the form of + * @return Multimap of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple - * rules for a pair of node types but the from/to value in the json is flipped for some of them. + * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ public Multimap getParentRules(String nodeType, SchemaVersion v) { Filter from = assembleFilterSegments(where(EdgeField.FROM.toString()).is(nodeType), getOppositeDirectionContainmentCriteria()); Filter to = assembleFilterSegments(where(EdgeField.TO.toString()).is(nodeType), getSameDirectionContainmentCriteria()); Filter total = from.or(to); - + return extractRules(total, v); } - + /** * Returns if the given node type has any parent relationships (ie it is contained by another node type) in the current version. * @param nodeType @@ -408,7 +501,7 @@ public class EdgeIngestor { public boolean hasParentRule(String nodeType) { return hasParentRule(nodeType, schemaVersions.getDefaultVersion()); } - + /** * Returns if the given node type has any parent relationships (ie it is contained by another node type) in the given version. * @param nodeType @@ -417,47 +510,57 @@ public class EdgeIngestor { public boolean hasParentRule(String nodeType, SchemaVersion v) { return !getParentRules(nodeType, v).isEmpty(); } - + /** * Applies the given filter to the DocumentContext(s) for the given version to extract * edge rules, and converts this extracted information into the Multimap form - * + * * @param filter - JsonPath filter to read the DocumentContexts with. May be null * to denote no filter, ie get all. * @param v - The schema version to extract from - * @return Multimap of node names keys to the EdgeRules where the key takes the form of + * @return Multimap of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple - * rules for a pair of node types but the from/to value in the json is flipped for some of them. + * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ private Multimap extractRules(Filter filter, SchemaVersion v) { - List> foundRules = new ArrayList<>(); - List docs = versionJsonFilesMap.get(v); - if (docs != null) { - for (DocumentContext doc : docs) { - if (filter == null) { - foundRules.addAll(doc.read(READ_ALL_START)); - } else { - foundRules.addAll(doc.read(READ_START, filter)); - } - } - } - - return convertToEdgeRules(foundRules); - } - + SchemaFilter schemaFilter = new SchemaFilter(filter, v); + try { + return cacheFilterStore.get(schemaFilter); + } catch (ExecutionException e) { + LOG.info("Encountered exception during the retrieval of the rules"); + return ArrayListMultimap.create(); + } + } + + public Multimap extractRules(SchemaFilter schemaFilter){ + List> foundRules = new ArrayList<>(); + List docs = versionJsonFilesMap.get(schemaFilter.getSchemaVersion()); + if (docs != null) { + for (DocumentContext doc : docs) { + if (schemaFilter.getFilter() == null) { + foundRules.addAll(doc.read(READ_ALL_START)); + } else { + foundRules.addAll(doc.read(READ_START, Filter.parse(schemaFilter.getFilter()))); + } + } + } + + return convertToEdgeRules(foundRules); + } + //-----filter building helpers-----// /** * ANDs together the given start criteria with each criteria in the pieces list, and * then ORs together these segments into one filter. - * + * * JsonPath doesn't have an OR method on Criteria, only on Filters, so assembling * a complete filter requires this sort of roundabout construction. - * + * * @param start - Criteria of the form where(from/to).is(nodeType) * (ie the start of any A&AI edge rule query) * @param pieces - Other Criteria to be applied @@ -474,91 +577,91 @@ public class EdgeIngestor { } return assembled; } - + /** * Builds the sub-Criteria for a containment edge rule query where the direction * and containment fields must match. - * + * * Used for getChildRules() where the container node type is in the "from" position and * for getParentRules() where the containee type is in the "to" position. - * + * * @return List covering property permutations defined with either notation or explicit direction */ private List getSameDirectionContainmentCriteria() { List crits = new ArrayList<>(); - + crits.add(where(EdgeField.CONTAINS.toString()).is(DirectionNotation.DIRECTION.toString())); - + crits.add(where(EdgeField.DIRECTION.toString()).is(Direction.OUT.toString()) .and(EdgeField.CONTAINS.toString()).is(Direction.OUT.toString())); - + crits.add(where(EdgeField.DIRECTION.toString()).is(Direction.IN.toString()) .and(EdgeField.CONTAINS.toString()).is(Direction.IN.toString())); - + return crits; } - + /** * Builds the sub-Criteria for a containment edge rule query where the direction * and containment fields must not match. - * + * * Used for getChildRules() where the container node type is in the "to" position and * for getParentRules() where the containee type is in the "from" position. - * + * * @return List covering property permutations defined with either notation or explicit direction */ private List getOppositeDirectionContainmentCriteria() { List crits = new ArrayList<>(); - + crits.add(where(EdgeField.CONTAINS.toString()).is(DirectionNotation.OPPOSITE.toString())); - + crits.add(where(EdgeField.DIRECTION.toString()).is(Direction.OUT.toString()) .and(EdgeField.CONTAINS.toString()).is(Direction.IN.toString())); - + crits.add(where(EdgeField.DIRECTION.toString()).is(Direction.IN.toString()) .and(EdgeField.CONTAINS.toString()).is(Direction.OUT.toString())); - + return crits; } - + //-----rule packaging helpers-----// /** * Converts the raw output from reading the json file to the Multimap format - * + * * @param allFound - raw edge rule output read from json file(s) * (could be empty if none found) - * @return Multimap of node names keys to the EdgeRules where the key takes the form of + * @return Multimap of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Will be empty if input * was empty. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple - * rules for a pair of node types but the from/to value in the json is flipped for some of them. + * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ private Multimap convertToEdgeRules(List> allFound) { Multimap rules = ArrayListMultimap.create(); - + TypeAlphabetizer alpher = new TypeAlphabetizer(); - + for (Map raw : allFound) { EdgeRule converted = new EdgeRule(raw); if (converted.getFrom().equals(converted.getTo())) { - /* the way the code worked in the past was with outs and - * when we switched it to in the same-node-type to - * same-node-type parent child edges were failing because all - * of the calling code would pass the parent as the left argument, - * so it was either in that method swap the parent/child, - * flip the edge rule or make all callers swap. the last seemed - * like a bad idea. and felt like the edge flip was the better + /* the way the code worked in the past was with outs and + * when we switched it to in the same-node-type to + * same-node-type parent child edges were failing because all + * of the calling code would pass the parent as the left argument, + * so it was either in that method swap the parent/child, + * flip the edge rule or make all callers swap. the last seemed + * like a bad idea. and felt like the edge flip was the better * of the remaining 2 */ converted.flipDirection(); } String alphabetizedKey = alpher.buildAlphabetizedKey(raw.get(EdgeField.FROM.toString()), raw.get(EdgeField.TO.toString())); rules.put(alphabetizedKey, converted); } - + return rules; } - + } diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRule.java b/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRule.java index e1cb240e..f914f6cb 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRule.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRule.java @@ -26,7 +26,9 @@ import org.onap.aai.edges.enums.EdgeField; import org.onap.aai.edges.enums.EdgeProperty; import org.onap.aai.edges.enums.MultiplicityRule; +import java.util.Collections; import java.util.EnumMap; +import java.util.HashMap; import java.util.Map; /** @@ -43,16 +45,16 @@ public class EdgeRule { private String description; private boolean isPrivateEdge = false; - /** + /** * Instantiates a new edge rule. - * + * * @param fieldVals - Map where first string is - * an EdgeField value and second string is the + * an EdgeField value and second string is the * value of that field */ public EdgeRule(Map fieldVals) { edgeFields = new EnumMap<>(EdgeProperty.class); - + from = fieldVals.get(EdgeField.FROM.toString()); to = fieldVals.get(EdgeField.TO.toString()); label = fieldVals.get(EdgeField.LABEL.toString()); @@ -63,19 +65,32 @@ public class EdgeRule { String rawVal = fieldVals.get(prop.toString()); edgeFields.put(prop, convertNotation(direction, rawVal)); } - + isDefaultEdge = Boolean.valueOf(fieldVals.get(EdgeField.DEFAULT.toString())); - + description = fieldVals.get(EdgeField.DESCRIPTION.toString()); if (description == null) { //bc description is optional and not in v12 and earlier description = ""; } } + // Copy Constructor + public EdgeRule(EdgeRule edgeRule){ + this.from = edgeRule.from; + this.to = edgeRule.to; + this.label = edgeRule.label; + this.direction = Direction.valueOf(edgeRule.direction.toString()); + this.multiplicityRule = MultiplicityRule.valueOf(edgeRule.multiplicityRule.toString()); + this.edgeFields = new HashMap<>(edgeRule.edgeFields); + this.isDefaultEdge = edgeRule.isDefaultEdge; + this.description = edgeRule.description; + this.isPrivateEdge = edgeRule.isPrivateEdge; + } + /** * Converts whatever string was in the json for an edge property value into * the appropriate AAIDirection - * + * * @param Direction dir - the edge direction * @param String rawVal - property value from the json, may be * IN, OUT, BOTH, NONE, ${direction}, or !${direction} @@ -92,7 +107,7 @@ public class EdgeRule { } else if (AAIDirection.IN.toString().equalsIgnoreCase(rawVal)) { return AAIDirection.IN; } - + DirectionNotation rawDN = DirectionNotation.getValue(rawVal); if (DirectionNotation.DIRECTION.equals(rawDN)) { return AAIDirection.getValue(dir); @@ -100,7 +115,7 @@ public class EdgeRule { return AAIDirection.getValue(dir.opposite()); } } - + /** * Gets the name of the node type in the "from" field * @return String nodetype @@ -125,7 +140,7 @@ public class EdgeRule { public String getLabel() { return label; } - + /** * Gets the multiplicity rule. * @@ -134,7 +149,7 @@ public class EdgeRule { public MultiplicityRule getMultiplicityRule() { return multiplicityRule; } - + /** * Gets the edge direction * @@ -143,7 +158,7 @@ public class EdgeRule { public Direction getDirection() { return direction; } - + /** * Gets the value of contains-other-v * @@ -152,7 +167,7 @@ public class EdgeRule { public String getContains() { return edgeFields.get(EdgeProperty.CONTAINS).toString(); } - + /** * Gets the value of delete-other-v * @@ -161,10 +176,10 @@ public class EdgeRule { public String getDeleteOtherV() { return edgeFields.get(EdgeProperty.DELETE_OTHER_V).toString(); } - + /** * Gets the value of the prevent-delete property - * + * * @return String prevent-delete property value */ public String getPreventDelete() { @@ -173,13 +188,13 @@ public class EdgeRule { /** * Returns if this rule is a default or not - * + * * @return boolean */ public boolean isDefault() { return isDefaultEdge; } - + /** * Gets the description on the edge rule (if there is one) * @return String description @@ -187,7 +202,7 @@ public class EdgeRule { public String getDescription() { return this.description; } - + /** * Flips the direction value * IN -> OUT diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRuleQuery.java b/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRuleQuery.java index 5801e816..58c8c546 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRuleQuery.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRuleQuery.java @@ -1,4 +1,4 @@ -/** +/** * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ @@ -36,6 +36,7 @@ import static com.jayway.jsonpath.Filter.filter; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import static com.jayway.jsonpath.Criteria.where; @@ -90,6 +91,12 @@ public class EdgeRuleQuery { 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) ) { @@ -312,6 +319,30 @@ public class EdgeRuleQuery { } 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); + } + } + } diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/edges/SchemaFilter.java b/aai-schema-ingest/src/main/java/org/onap/aai/edges/SchemaFilter.java new file mode 100644 index 00000000..792e3c51 --- /dev/null +++ b/aai-schema-ingest/src/main/java/org/onap/aai/edges/SchemaFilter.java @@ -0,0 +1,69 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-18 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.edges; + +import com.jayway.jsonpath.Filter; +import org.onap.aai.setup.SchemaVersion; + +import java.util.Objects; + +public class SchemaFilter { + + private String filter; + + private SchemaVersion schemaVersion; + + public SchemaFilter(Filter filter, SchemaVersion schemaVersion){ + if(filter != null){ + this.filter = filter.toString(); + } + this.schemaVersion = schemaVersion; + } + + public SchemaVersion getSchemaVersion() { + return schemaVersion; + } + + public String getFilter() { + return filter; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SchemaFilter that = (SchemaFilter) o; + return Objects.equals(filter, that.filter) && + Objects.equals(schemaVersion, that.schemaVersion); + } + + @Override + public int hashCode() { + return Objects.hash(filter, schemaVersion); + } + + @Override + public String toString() { + return "SchemaFilter{" + + "filter='" + filter + '\'' + + ", schemaVersion=" + schemaVersion + + '}'; + } +} diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/AmbiguousRuleChoiceException.java b/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/AmbiguousRuleChoiceException.java index b218cecd..3ddced9a 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/AmbiguousRuleChoiceException.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/AmbiguousRuleChoiceException.java @@ -1,4 +1,4 @@ -/** +/** * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ @@ -24,4 +24,8 @@ public class AmbiguousRuleChoiceException extends Exception { public AmbiguousRuleChoiceException(String msg) { super(msg); } + + public AmbiguousRuleChoiceException(Throwable throwable){ + super(throwable); + } } diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/EdgeRuleNotFoundException.java b/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/EdgeRuleNotFoundException.java index 4d339de2..de022bc5 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/EdgeRuleNotFoundException.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/EdgeRuleNotFoundException.java @@ -1,4 +1,4 @@ -/** +/** * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ @@ -24,4 +24,8 @@ public class EdgeRuleNotFoundException extends Exception { public EdgeRuleNotFoundException(String msg) { super(msg); } + + public EdgeRuleNotFoundException(Throwable throwable){ + super(throwable); + } } -- cgit 1.2.3-korg