Remove any remaining db edge rules references
[aai/aai-common.git] / aai-core / src / main / java / org / openecomp / aai / serialization / db / EdgeRules.java
index 454aa1e..f819b9e 100644 (file)
@@ -24,14 +24,14 @@ import static com.jayway.jsonpath.Criteria.where;
 import static com.jayway.jsonpath.Filter.filter;
 
 import java.io.InputStream;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumMap;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Optional;
 import java.util.Scanner;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
@@ -40,7 +40,6 @@ import org.apache.tinkerpop.gremlin.structure.Direction;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 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;
@@ -57,9 +56,7 @@ import com.jayway.jsonpath.JsonPath;
 public class EdgeRules {
        
        private EELFLogger logger = EELFManager.getInstance().getLogger(EdgeRules.class);
-       
-       private Multimap<String, String> deleteScope =  DbEdgeRules.DefaultDeleteScope;
-       
+
        private DocumentContext rulesDoc;
        
        /**
@@ -74,22 +71,28 @@ public class EdgeRules {
                
        }
        
+       private EdgeRules(String rulesFilename) {
+               String json = this.getEdgeRuleJson(rulesFilename);
+               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);
-               
-               if (!Version.isLatest(version)) {
-                       try {
-                               Class<?> dbEdgeRules = Class.forName("org.openecomp.aai.dbmodel." + version.toString() + ".gen.DbEdgeRules");
-                               this.deleteScope = (Multimap<String, String>)dbEdgeRules.getDeclaredField("DefaultDeleteScope").get(null);      
-                       } catch (Exception e) {
-                       }
-               }
        }
        
        private String getEdgeRuleJson(Version version) {
@@ -105,6 +108,11 @@ public class EdgeRules {
        private static class Helper {
                private static final EdgeRules INSTANCE = new EdgeRules();
                private static final Map<Version, EdgeRules> INSTANCEMAP = new ConcurrentHashMap<>();
+
+               private static EdgeRules getEdgeRulesByFilename(String rulesFilename) {
+                       return new EdgeRules(rulesFilename);
+               }
+
                private static EdgeRules getVersionedEdgeRules(Version v) {
                        if (Version.isLatest(v)) {
                                return INSTANCE;
@@ -136,6 +144,16 @@ public class EdgeRules {
 
        }
        
+       /**
+        * Loads edge rules from the given file.
+        *
+        * @param rulesFilename - name of the file to load rules from
+        * @return the EdgeRules instance
+        */
+       public static EdgeRules getInstance(String rulesFilename) {
+               return Helper.getEdgeRulesByFilename(rulesFilename);
+       }
+
        /**
         * Adds the tree edge.
         *
@@ -230,21 +248,10 @@ public class EdgeRules {
                // 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<String, String> propMap = rule.getEdgeProperties();
+               Map<EdgeProperty, String> propMap = rule.getEdgeProperties();
                
-               for (String key : propMap.keySet()) {
-                       String revKeyname = key + "-REV";
-                       String triple = propMap.get(key);
-                       if(triple.equals("true")){
-                               edge.property(key, true);
-                               edge.property(revKeyname,false);
-                       } else if (triple.equals("false")) {
-                               edge.property(key, false);
-                               edge.property(revKeyname,false);
-                       } else if (triple.equals("reverse")) {
-                               edge.property(key, false);
-                               edge.property(revKeyname,true);
-                       }
+               for (Entry<EdgeProperty, String> entry : propMap.entrySet()) {
+                       edge.property(entry.getKey().toString(), entry.getValue());
                }
        }
        
@@ -263,8 +270,8 @@ public class EdgeRules {
                                where("from").is(nodeB).and("to").is(nodeA)
                                );
                
-               List<Object> results = rulesDoc.read("$.rules.[?]", aToB);
-               results.addAll(rulesDoc.read("$.rules.[?]", bToA));
+               List<Map<String, String>> results = readRules(aToB);
+               results.addAll(readRules(bToA));
 
                return !results.isEmpty();
                
@@ -311,6 +318,8 @@ public class EdgeRules {
                return result;
        }
        
+
+
        /**
         * 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
@@ -324,19 +333,21 @@ public class EdgeRules {
         */
        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));
+               List<Map<String, String>> aToBEdges = readRules(buildFilter(type, nodeA, nodeB));
                if (!aToBEdges.isEmpty()) {
                        //lazily stop iterating if we find a match
                        //should there be a mismatch between type and isParent,
                        //the caller will receive something.
                        //this operates on the assumption that there are at most two rules
                        //for a given vertex pair
+                       verifyRule(aToBEdges.get(0));
                        return buildRule(aToBEdges.get(0));
                }
                
                //we get here if there was nothing for A to B, so let's try B to A
-               List<Map<String, String>> bToAEdges = rulesDoc.read("$.rules.[?]", buildFilter(type, nodeB, nodeA));
+               List<Map<String, String>> bToAEdges = readRules(buildFilter(type, nodeB, nodeA));
                if (!bToAEdges.isEmpty()) {
+                       verifyRule(bToAEdges.get(0));
                        return flipDirection(buildRule(bToAEdges.get(0))); //bc we need to return as A|B, so flip the direction to match
                }
                
@@ -355,12 +366,12 @@ public class EdgeRules {
        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")
+                                       where("from").is(nodeA).and("to").is(nodeB).and(EdgeProperty.CONTAINS.toString()).is(AAIDirection.NONE.toString())
                                        );
                } 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")       
+                                       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}")   
                                        );
                }
        }
@@ -371,15 +382,19 @@ public class EdgeRules {
         * @param edge - the edge information returned from JsonPath
         * @return EdgeRule containing that information
         */
-       private EdgeRule buildRule(Map<String, String> edge) {
+       private EdgeRule buildRule(Map<String, String> map) {
+               Map<String, String> edge = new EdgePropertyMap<>();
+               edge.putAll(map);
+               
                EdgeRule rule = new EdgeRule();
                rule.setLabel(edge.get("label"));
                rule.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"));
+               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()));
+               
                return rule;
        }
        
@@ -423,20 +438,6 @@ public class EdgeRules {
                
        }
        
-       /**
-        * Gets the delete semantic.
-        *
-        * @param nodeType the node type
-        * @return the delete semantic
-        */
-       public DeleteSemantic getDeleteSemantic(String nodeType) {
-               Collection<String> semanticCollection = deleteScope.get(nodeType);
-               String semantic = semanticCollection.iterator().next();
-               
-               return DeleteSemantic.valueOf(semantic);
-               
-       }
-       
        /**
         * Validate multiplicity.
         *
@@ -488,6 +489,61 @@ public class EdgeRules {
                                
        }
        
+       /**
+        * Verifies that all required properties are defined in the given edge rule.
+        * If they are not, throws a RuntimeException.
+        *
+        * @param rule - Map<String edge property, String edge property value> representing
+        * an edge rule
+        */
+       private void verifyRule(Map<String, String> rule) {
+               for (EdgeProperty prop : EdgeProperty.values()) {
+                       if (!rule.containsKey(prop.toString())) {
+                               /* Throws RuntimeException as rule definition errors
+                                * cannot be recovered from, and should never happen anyway
+                                * because these are configuration files, so requiring all
+                                * downstream code to check for this exception seems inappropriate.
+                                * It's instantiated with an AAIException to make sure all
+                                * relevant information is present in the error message.
+                                */
+                               throw new RuntimeException(new AAIException("AAI_4005",
+                                               "Rule between " + rule.get("from") + " and " + rule.get("to") +
+                                               " is missing property " + prop + "."));
+                       }
+               }
+       }
+
+       /**
+        * Reads all the edge rules from the loaded json file.
+        *
+        * @return List<Map<String edge property, String edge property value>>
+        *  Each map represents a rule read from the json.
+        */
+       private List<Map<String, String>> readRules() {
+               return readRules(null);
+       }
+
+       /**
+        * Reads the edge rules from the loaded json file, using the given filter
+        * to get specific rules. If filter is null, will get all rules.
+        *
+        * @param filter - may be null to indicate get all
+        * @return List<Map<String edge property, String edge property value>>
+        *  Each map represents a rule read from the json.
+        */
+       private List<Map<String, String>> readRules(Filter filter) {
+               List<Map<String, String>> results;
+               if (filter == null) { //no filter means get all
+                       results = rulesDoc.read("$.rules.*");
+               } else {
+                       results = rulesDoc.read("$.rules.[?]", filter);
+               }
+               for (Map<String, String> result : results) {
+                       verifyRule(result);
+               }
+               return results;
+       }
+
        /**
         * Gets all the edge rules we define.
         * 
@@ -496,7 +552,7 @@ public class EdgeRules {
        public Multimap<String, EdgeRule> getAllRules() {
                Multimap<String, EdgeRule> result = ArrayListMultimap.create();
                
-               List<Map<String, String>> rules = rulesDoc.read("$.rules.*");
+               List<Map<String, String>> rules = readRules();
                for (Map<String, String> rule : rules) {
                        EdgeRule er = buildRule(rule);
                        String name = rule.get("from") + "|" + rule.get("to");
@@ -506,8 +562,27 @@ public class EdgeRules {
                return result;
        }
        
-       public Multimap<String, String> getDeleteSemantics() {
-               return this.deleteScope;
-       }
+       /**
+        * Gets all edge rules that define a child relationship from
+        * the given node type.
+        *
+        * @param nodeType
+        * @return
+        */
+       public Set<EdgeRule> getChildren(String nodeType) {
+               
+               final Filter filter = filter(
+                               where("from").is(nodeType).and(EdgeProperty.CONTAINS.toString()).is("${direction}")
+                               ).or(where("to").is(nodeType).and(EdgeProperty.CONTAINS.toString()).is("!${direction}"));
+               
+               final List<Map<String, String>> rules = readRules(filter);
+               final Set<EdgeRule> result = new HashSet<>();
+               rules.forEach(item -> {
+                       verifyRule(item);
+                       result.add(buildRule(item));
+               });
        
+               return result;
+               
+       }
 }