diff options
author | Threefoot, Jane (jt6620) <jt6620@att.com> | 2017-07-31 15:49:04 -0400 |
---|---|---|
committer | Threefoot, Jane (jt6620) <jt6620@att.com> | 2017-07-31 15:52:53 -0400 |
commit | 9941d0d8597d9d69954819ca9458962aee281b10 (patch) | |
tree | c48876e6a16b10920259287fe3ec51436f94b864 /aai-core/src/main/java | |
parent | a9320e7933bc04954264d9f3f34b9cb904b61353 (diff) |
[AAI-100 Amsterdam] refactored dbedgerules
Change-Id: I778a56f525cba0ebd39d24d366fc9f0935be71f2
Signed-off-by: Threefoot, Jane (jt6620) <jt6620@att.com>
Diffstat (limited to 'aai-core/src/main/java')
7 files changed, 514 insertions, 170 deletions
diff --git a/aai-core/src/main/java/org/openecomp/aai/dbgen/SchemaGenerator.java b/aai-core/src/main/java/org/openecomp/aai/dbgen/SchemaGenerator.java index 63606017..c5186b01 100644 --- a/aai-core/src/main/java/org/openecomp/aai/dbgen/SchemaGenerator.java +++ b/aai-core/src/main/java/org/openecomp/aai/dbgen/SchemaGenerator.java @@ -96,16 +96,12 @@ public class SchemaGenerator{ Multimap<String, EdgeRule> edges = null; Set<String> labels = new HashSet<>(); - try { - edges = EdgeRules.getInstance().getAllRules(); - for (EdgeRule rule : edges.values()) { - labels.add(rule.getLabel()); - } - } catch (AAIException e) { - LOGGER.error("could not get edge rules", e); - System.out.println("could not get edge rules"); - System.exit(1); + + edges = EdgeRules.getInstance().getAllRules(); + for (EdgeRule rule : edges.values()) { + labels.add(rule.getLabel()); } + for( String label: labels){ if( graphMgmt.containsRelationType(label) ) { String dmsg = " EdgeLabel [" + label + "] already existed. "; diff --git a/aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRules.java b/aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRules.java index f4b55504..2ab378e2 100644 --- a/aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRules.java +++ b/aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRules.java @@ -424,49 +424,4 @@ public class DbEdgeRules { .putAll("license","THIS_NODE_ONLY") .putAll("zone", "THIS_NODE_ONLY") .putAll("route-target", "CASCADE_TO_CHILDREN").build(); - - // NOTE -- Sorry, this is ugly, but we are mapping the nodeTypeCategory two - // ways just to - // make the code a little less bulky. But that means that we need to ensure - // that - // nodeTypeCategory and nodeTypeCatMap are kept in synch. - - // NodeTypeCategory: key is: nodeTypeCategory, value is: - // "nodeTypes,keyProperties,AltKeyProps,depNode4UniquenessFlag" - public static final Multimap<String, String> NodeTypeCategory = new ImmutableSetMultimap.Builder<String, String>() - .putAll("vnf", "vce|vpe|generic-vnf,vnf-id,,true").build(); - - // NodeTypeCatMap: key is nodeType; value is: "nodeTypeCategory" - // So -- we're assuming that a nodeType can only be in one nodeTypeCategory. - public static final Map<String, String> NodeTypeCatMap; - static { - NodeTypeCatMap = new HashMap<String, String>(); - NodeTypeCatMap.put("vpe", "vnf"); - NodeTypeCatMap.put("vce", "vnf"); - NodeTypeCatMap.put("generic-vnf", "vnf"); - } - - // ReservedPropNames: keys are property names of (node) properties that are - // common to all nodes and - // should not be removed if not passed in on an UPDATE request. - public static final Map<String, String> ReservedPropNames; - static { - ReservedPropNames = new HashMap<String, String>(); - ReservedPropNames.put("source-of-truth", ""); - ReservedPropNames.put("last-mod-source-of-truth", ""); - ReservedPropNames.put("aai-created-ts", ""); - ReservedPropNames.put("aai-last-mod-ts", ""); - } - - // This just lists which node types can be connected to themselves recursively. - // It's temporary - since DbEdgeRules is going to be overhauled in 16-10, this will - // get generated automatically. But for 1607, it can work like this. - public static final Map<String, String> CanBeRecursiveNT; - static { - CanBeRecursiveNT = new HashMap<String, String>(); - CanBeRecursiveNT.put("model-element", ""); - CanBeRecursiveNT.put("service-instance", ""); - CanBeRecursiveNT.put("named-query-element", ""); - } - } diff --git a/aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRulesConverter.java b/aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRulesConverter.java new file mode 100644 index 00000000..bbb456bd --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/dbmodel/DbEdgeRulesConverter.java @@ -0,0 +1,222 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 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.openecomp.aai.dbmodel; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.openecomp.aai.introspection.Version; + +import com.google.common.collect.Multimap; + +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import freemarker.template.TemplateExceptionHandler; + +/** + * Converts the old DbEdgeRules multimap to new json format + */ +public class DbEdgeRulesConverter { + private static final int LABEL = 0; + private static final int DIRECTION = 1; + private static final int MULTIPLICITY = 2; + private static final int ISPARENT = 3; + private static final int USESRESOURCE = 4; + private static final int HASDELTARGET = 5; + private static final int SVCINFRA = 6; + + private Configuration config = new Configuration(); + private Template template; + private String destDirectory; + private FileOutputStream writeStream; + + public DbEdgeRulesConverter(){ /*pretty much just so I can test functionality without dealing with template setup*/ } + + public DbEdgeRulesConverter(String destinationDir) { + destDirectory = destinationDir; + try { + setup(destinationDir); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Sets up the freemarker template and the directory to be written to. Run this once before + * doing any converting, does not need to be run per file generated (unless you want different directories for each file). + * + * @param destinationDir - String of the path to the directory where you want the new format files written to, + * relative to aai-core/ + * @throws IOException if it can't find the template loading directory or the template file itself + */ + public void setup(String destinationDir) throws IOException { + config.setDirectoryForTemplateLoading(new File("src/main/resources/dbedgerules/conversion")); + config.setDefaultEncoding("UTF-8"); + config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); + template = config.getTemplate("edgerulesTemplate.ftlh"); + + File destination = new File(destinationDir); + if (!destination.exists()) { + destination.mkdir(); + } + } + + /** + * Converts the given DbEdgeRules multimap representation into a json file of the new format. + * + * @param rules - a Multimap<String, String> of the old DbEdgeRules format + * @param writer - writes to the output file (designate that file when you instantiate the writer) + */ + public void convert(Multimap<String, String> rules, Writer writer) { + + List<EdgeRuleBean> rulesToWrite = new ArrayList<>(); + for (Entry<String, String> rule : rules.entries()) { + rulesToWrite.add(extractData(rule)); + } + Map<String, List<EdgeRuleBean>> wrappedRules = new HashMap<>(); + wrappedRules.put("wrappedRules", rulesToWrite); + try { + template.process(wrappedRules, writer); + } catch (TemplateException e) { + System.out.println("Something went wrong when trying to combine the data and the template"); + e.printStackTrace(); + } catch (IOException e) { + System.out.println("There was a problem writing to the output file"); + e.printStackTrace(); + } + } + + /** + * Extracts the pieces of information that go in each field of the new json format from the old + * DbEdgeRules format. + * + * @param rule - one <String, String> entry from the DbEdgeRules multimap representation + * Takes the form <"from-node|to-node", "label,direction,multiplicity,isParent,usesResource,hasDelTarget,svc-infra"> + * @return EdgeRuleBean with the pieces of information the template needs, in a format the template can understand + */ + public EdgeRuleBean extractData(Entry<String, String> rule){ + EdgeRuleBean data = new EdgeRuleBean(); + + String oldName = rule.getKey(); + String[] nodes = oldName.split("\\|"); + data.setFrom(nodes[0]); + data.setTo(nodes[1]); + + String oldSpecs = rule.getValue(); + String[] specs = oldSpecs.split(","); + data.setLabel(specs[LABEL]); + data.setDirection(specs[DIRECTION]); + data.setMultiplicity(specs[MULTIPLICITY]); + data.setParent(specs[ISPARENT]); + data.setUsesResource(specs[USESRESOURCE]); + data.setHasDelTarget(specs[HASDELTARGET]); + data.setSvcInfra(specs[SVCINFRA]); + + return data; + } + + private Multimap<String, String> getEdgeRules(Version v) { + try { + Class <?> dbEdgeRules; + //use reflection to get the corresponding DbEdgeRules class + //need this weird if-else bc current version doesn't sit in a v.gen subdirectory + if (Version.isLatest(v)) { + dbEdgeRules = Class.forName("org.openecomp.aai.dbmodel.DbEdgeRules"); + } else { + dbEdgeRules = Class.forName("org.openecomp.aai.dbmodel." + v + ".gen.DbEdgeRules"); + } + + @SuppressWarnings("unchecked") + Multimap<String, String> rules = (Multimap<String,String>)dbEdgeRules.getDeclaredField("EdgeRules").get(null); + + return rules; + } catch (ClassNotFoundException e) { + System.out.println("could not find DbEdgeRules class for version " + v); + e.printStackTrace(); + return null; + } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { + System.out.println("Something went wrong trying to retrieve the rules"); + e.printStackTrace(); + return null; + } + } + + private Writer buildOutputWriter(Version v) { + try { + File output = new File(destDirectory + "DbEdgeRules_" + v + ".json"); + writeStream = new FileOutputStream(output); + return new OutputStreamWriter(writeStream); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Runs all the conversion steps for the specified version. + * + * @param v + */ + public void convertVersion(Version v) { + try { + Multimap<String, String> rules = getEdgeRules(v); + if (rules == null) { //something went wrong, we've already logged it in the helper so just stop execution + return; + } + + Writer writer = buildOutputWriter(v); + if (writer == null) { //something went wrong, we've already logged it in the helper so just stop execution + return; + } + convert(rules, writer); + + writer.close(); + writeStream.close(); + } catch (IOException e) { + System.out.println("Something went wrong closing the writer/writestream"); + e.printStackTrace(); + } + } + + /** + * Runs the converter for each DbEdgeRules version currently supported (2, 7, 8, 9, and 10) + * + * @param args - none actually + */ + public static void main(String[] args) { + String destDirectory = "src/main/resources/dbedgerules/"; + DbEdgeRulesConverter dberConverter = new DbEdgeRulesConverter(destDirectory); + + for (Version v : Version.values()) { + dberConverter.convertVersion(v); + } + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/dbmodel/EdgeRuleBean.java b/aai-core/src/main/java/org/openecomp/aai/dbmodel/EdgeRuleBean.java new file mode 100644 index 00000000..f80bbca9 --- /dev/null +++ b/aai-core/src/main/java/org/openecomp/aai/dbmodel/EdgeRuleBean.java @@ -0,0 +1,88 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 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.openecomp.aai.dbmodel; + +public class EdgeRuleBean { + private String from; + private String to; + private String label; + private String direction; + private String multiplicity; + private String isParent; + private String usesResource; + private String hasDelTarget; + private String svcInfra; + + public String getFrom() { + return from; + } + public void setFrom(String from) { + this.from = from; + } + public String getTo() { + return to; + } + public void setTo(String to) { + this.to = to; + } + public String getLabel() { + return label; + } + public void setLabel(String label) { + this.label = label; + } + public String getDirection() { + return direction; + } + public void setDirection(String direction) { + this.direction = direction; + } + public String getMultiplicity() { + return multiplicity; + } + public void setMultiplicity(String multiplicity) { + this.multiplicity = multiplicity; + } + public String getIsParent() { + return isParent; + } + public void setParent(String isParent) { + this.isParent = isParent; + } + public String getUsesResource() { + return usesResource; + } + public void setUsesResource(String usesResource) { + this.usesResource = usesResource; + } + public String getHasDelTarget() { + return hasDelTarget; + } + public void setHasDelTarget(String hasDelTarget) { + this.hasDelTarget = hasDelTarget; + } + public String getSvcInfra() { + return svcInfra; + } + public void setSvcInfra(String svcInfra) { + this.svcInfra = svcInfra; + } +} diff --git a/aai-core/src/main/java/org/openecomp/aai/introspection/Version.java b/aai-core/src/main/java/org/openecomp/aai/introspection/Version.java index b0f6f55d..8c7998b5 100644 --- a/aai-core/src/main/java/org/openecomp/aai/introspection/Version.java +++ b/aai-core/src/main/java/org/openecomp/aai/introspection/Version.java @@ -25,4 +25,12 @@ public enum Version { v9, v10, v11; + + public static boolean isLatest(Version v) { + return (Version.v11.equals(v)); //TODO update when we increment the version, or find a better way of doing this + } + + public static Version getLatest(){ + return Version.v11; //TODO update when we increment the version, or find a better way of doing this + } } diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRule.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRule.java index 6d0acc6a..12548f9c 100644 --- a/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRule.java +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRule.java @@ -70,6 +70,18 @@ public class EdgeRule { return multiplicityRule; } + public void setMultiplicityRule(String multiplicity){ + if ("Many2Many".equalsIgnoreCase(multiplicity)) { + this.multiplicityRule = MultiplicityRule.MANY2MANY; + } else if ("One2Many".equalsIgnoreCase(multiplicity)) { + this.multiplicityRule = MultiplicityRule.ONE2MANY; + } else if ("One2One".equalsIgnoreCase(multiplicity)) { + this.multiplicityRule = MultiplicityRule.ONE2ONE; + } else { //should be "Many2One" + this.multiplicityRule = MultiplicityRule.MANY2ONE; + } + } + /** * Sets the multiplicity rule. * @@ -88,6 +100,16 @@ public class EdgeRule { return direction; } + public void setDirection(String direction){ + if ("OUT".equalsIgnoreCase(direction)) { + this.direction = Direction.OUT; + } else if ("IN".equalsIgnoreCase(direction)) { + this.direction = Direction.IN; + } else { + this.direction = Direction.BOTH; + } + } + /** * Sets the direction. * diff --git a/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRules.java b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRules.java index 9e4e8396..7f925a16 100644 --- a/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRules.java +++ b/aai-core/src/main/java/org/openecomp/aai/serialization/db/EdgeRules.java @@ -20,13 +20,16 @@ package org.openecomp.aai.serialization.db; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; +import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; import org.apache.tinkerpop.gremlin.structure.Direction; @@ -36,32 +39,49 @@ import org.apache.tinkerpop.gremlin.structure.Vertex; import org.openecomp.aai.db.props.AAIProperties; import org.openecomp.aai.dbmodel.DbEdgeRules; import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Version; import org.openecomp.aai.serialization.db.exceptions.EdgeMultiplicityException; import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; +import com.jayway.jsonpath.JsonPath; -public class EdgeRules { +import static com.jayway.jsonpath.Filter.filter; +import static com.jayway.jsonpath.Criteria.where; + +import com.jayway.jsonpath.DocumentContext; +import com.jayway.jsonpath.Filter; + +import java.util.Scanner; - private Multimap<String, String> rules = DbEdgeRules.EdgeRules; +public class EdgeRules { + + private EELFLogger logger = EELFManager.getInstance().getLogger(EdgeRules.class); + private Multimap<String, String> deleteScope = DbEdgeRules.DefaultDeleteScope; - private final int EDGE_NAME = 0; - private final int DIRECTION = 1; - private final int MULTIPLICITY_RULE = 2; - private final int IS_PARENT = 3; - private final int USES_RESOURCE = 4; - private final int HAS_DEL_TARGET = 5; - private final int SVC_INFRA = 6; + + private DocumentContext rulesDoc; /** - * Instantiates a new edge rules. + * Loads the most recent DbEdgeRules json file for later parsing. + * Only need most recent version for actual A&AI operations that call this class; + * the old ones are only used in tests. */ private EdgeRules() { - + + InputStream is = getClass().getResourceAsStream("/dbedgerules/DbEdgeRules_" + Version.getLatest().toString() + ".json"); + + Scanner scanner = new Scanner(is); + String json = scanner.useDelimiter("\\Z").next(); + scanner.close(); + rulesDoc = JsonPath.parse(json); } + private static class Helper { private static final EdgeRules INSTANCE = new EdgeRules(); - } /** @@ -81,7 +101,6 @@ public class EdgeRules { * @param bVertex the in vertex * @return the edge * @throws AAIException the AAI exception - * @throws NoEdgeRuleFoundException */ public Edge addTreeEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException { return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex, false); @@ -94,7 +113,6 @@ public class EdgeRules { * @param bVertex the in vertex * @return the edge * @throws AAIException the AAI exception - * @throws NoEdgeRuleFoundException */ public Edge addEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException { return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex, false); @@ -107,7 +125,6 @@ public class EdgeRules { * @param bVertex the in vertex * @return the edge * @throws AAIException the AAI exception - * @throws NoEdgeRuleFoundException */ public Edge addTreeEdgeIfPossible(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException { return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex, true); @@ -120,7 +137,6 @@ public class EdgeRules { * @param bVertex the in vertex * @return the edge * @throws AAIException the AAI exception - * @throws NoEdgeRuleFoundException */ public Edge addEdgeIfPossible(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException { return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex, true); @@ -134,9 +150,8 @@ public class EdgeRules { * @param bVertex the in vertex * @return the edge * @throws AAIException the AAI exception - * @throws NoEdgeRuleFoundException */ - private Edge addEdge(EdgeType type, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex, boolean isBestEffort) throws AAIException, NoEdgeRuleFoundException { + private Edge addEdge(EdgeType type, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex, boolean isBestEffort) throws AAIException { EdgeRule rule = this.getEdgeRule(type, aVertex, bVertex); @@ -192,35 +207,53 @@ public class EdgeRules { } /** - * Checks for edge rule. + * Checks if any edge rules exist between the two given nodes, in either A|B or B|A order. * - * @param outType the out type - * @param inType the in type - * @return true, if successful + * @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 outType, String inType) { + 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) + ); - Collection<String> collection = rules.get(outType + "|" + inType); + List<Object> results = rulesDoc.read("$.rules.[?]", aToB); + results.addAll(rulesDoc.read("$.rules.[?]", bToA)); - return !collection.isEmpty(); + return !results.isEmpty(); } /** - * Checks for edge rule. + * Checks if any edge rules exist between the two given nodes, in either A|B or B|A order. * - * @param aVertex the out vertex - * @param bVertex the in vertex - * @return true, if successful + * @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 hasEdgeRule(Vertex aVertex, Vertex bVertex) { - String outType = (String)aVertex.<String>property("aai-node-type").orElse(null); - String inType = (String)bVertex.<String>property("aai-node-type").orElse(null); + 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); } + /** + * Gets all the edge rules 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 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) throws AAIException { Map<String, EdgeRule> result = new HashMap<>(); EdgeRule rule = null; @@ -235,95 +268,113 @@ public class EdgeRules { return result; } + /** - * Gets the edge rule. + * 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 + * to match the expected A|B return. * - * @param outType the out type - * @param inType the in type - * @return the edge rule - * @throws AAIException the AAI exception + * @param type - the type of edge you're looking for + * @param nodeA - first node type + * @param nodeB - second node type + * @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, String outType, String inType) throws AAIException { - EdgeRule rule = new EdgeRule(); - Collection<String> collection = null; - boolean isFlipped = false; - if (this.hasEdgeRule(outType, inType) || this.hasEdgeRule(inType, outType)) { - } else { - String detail = "No EdgeRule found for passed nodeTypes: " + outType + ", " + inType + "."; - throw new AAIException("AAI_6120", detail); - } - String key = outType + "|" + inType; - collection = rules.get(key); - - String[] info = null; - Iterator<String> iterator = collection.iterator(); - info = this.findRuleForContext(type, key, iterator); - if (info == null) { //didn't find anything in that order, look again - key = inType + "|" + outType; - collection = rules.get(key); - iterator = collection.iterator(); - info = this.findRuleForContext(type, key, iterator); - isFlipped = true; - } - if (info == null) { - throw new NoEdgeRuleFoundException("No EdgeRule found for EdgeType: " + type + " and node types: " + outType + " " + inType); - } - rule.setLabel(info[this.EDGE_NAME]); - rule.setMultiplicityRule(MultiplicityRule.valueOf(info[this.MULTIPLICITY_RULE].toUpperCase())); - rule.setHasDelTarget(info[this.HAS_DEL_TARGET]); - rule.setUsesResource(info[this.USES_RESOURCE]); - rule.setIsParent(info[this.IS_PARENT]); - rule.setServiceInfrastructure(info[this.SVC_INFRA]); - Direction direction = Direction.valueOf(info[this.DIRECTION]); - if (isFlipped && direction.equals(Direction.OUT)) { - rule.setDirection(Direction.IN); - } else if (isFlipped && direction.equals(Direction.IN)){ - rule.setDirection(Direction.OUT); - } else { - rule.setDirection(direction); - } - - return rule; - } - - private String[] findRuleForContext (EdgeType type, String key, Iterator<String> itr) { - String[] result = null; - String s = ""; - String isParent = ""; - String[] info = new String[10]; - while (itr.hasNext()) { - s = itr.next(); - info = s.split(","); - isParent = info[this.IS_PARENT]; + public EdgeRule getEdgeRule(EdgeType type, String nodeA, String nodeB) throws AAIException { + //try A to B + List<Map<String, String>> aToBEdges = rulesDoc.read("$.rules.[?]", 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 - if (type.equals(EdgeType.TREE) && (isParent.equals("true") || isParent.equals("reverse"))) { - result = info; - break; - } else if (type.equals(EdgeType.COUSIN) && isParent.equals("false")) { - result = info; - break; - } + 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 = rulesDoc.read("$.rules.[?]", buildFilter(type, nodeB, nodeA)); + if (!bToAEdges.isEmpty()) { + return flipDirection(buildRule(bToAEdges.get(0))); //bc we need to return as A|B, so flip the direction to match + } - return result; + //found none + throw new NoEdgeRuleFoundException("no " + type.toString() + " edge between " + nodeA + " and " + nodeB); + } + + /** + * 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) { + if (EdgeType.COUSIN.equals(type)) { + return filter( + where("from").is(nodeA).and("to").is(nodeB).and("isParent").is("false") + ); + } else { + return filter( + where("from").is(nodeA).and("to").is(nodeB).and("isParent").is("true")).or( + where("from").is(nodeA).and("to").is(nodeB).and("isParent").is("reverse") + ); + } + } + + /** + * Puts the give edge rule information into an EdgeRule object. + * + * @param edge - the edge information returned from JsonPath + * @return EdgeRule containing that information + */ + private EdgeRule buildRule(Map<String, String> edge) { + EdgeRule rule = new EdgeRule(); + rule.setLabel(edge.get("label")); + rule.setDirection(edge.get("direction")); + rule.setMultiplicityRule(edge.get("multiplicity")); + rule.setIsParent(edge.get("isParent")); + rule.setUsesResource(edge.get("usesResource")); + rule.setHasDelTarget(edge.get("hasDelTarget")); + rule.setServiceInfrastructure(edge.get("SVC-INFRA")); + 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 + */ + private EdgeRule flipDirection(EdgeRule rule) { + if (Direction.IN.equals(rule.getDirection())) { + rule.setDirection(Direction.OUT); + return rule; + } else if (Direction.OUT.equals(rule.getDirection())) { + rule.setDirection(Direction.IN); + return rule; + } else { //direction is BOTH, flipping both is still both + return rule; + } } + /** - * Gets the edge rule. + * 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 + * to match the expected A|B return. * - * @param aVertex the out vertex - * @param bVertex the in vertex - * @return the edge rule - * @throws AAIException the AAI exception - * @throws NoEdgeRuleFoundException + * @param type - the type of edge you're looking for + * @param aVertex - first node type + * @param bVertex - second node type + * @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) throws AAIException, NoEdgeRuleFoundException { - String outType = (String)aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null); - String inType = (String)bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null); + public EdgeRule getEdgeRule(EdgeType type, Vertex aVertex, Vertex bVertex) 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); @@ -386,7 +437,7 @@ public class EdgeRules { } - if (!detail.equals("")) { + if (!"".equals(detail)) { return Optional.of(detail); } else { return Optional.empty(); @@ -395,17 +446,19 @@ public class EdgeRules { } - public Multimap<String, EdgeRule> getAllRules() throws AAIException { - + /** + * 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(); - for (String key : this.rules.keySet()) { - String outType = ""; - String inType = ""; - String[] split = key.split("\\|"); - outType = split[0]; - inType = split[1]; - result.putAll(key,this.getEdgeRules(outType, inType).values()); + List<Map<String, String>> rules = rulesDoc.read("$.rules.*"); + for (Map<String, String> rule : rules) { + EdgeRule er = buildRule(rule); + String name = rule.get("from") + "|" + rule.get("to"); + result.put(name, er); } return result; |