Initial commit with all the necessary files
[aai/aai-common.git] / aai-core / src / main / java / org / openecomp / aai / serialization / db / EdgeRules.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * org.openecomp.aai
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11      http://www.apache.org/licenses/LICENSE-2.0
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.aai.serialization.db;
22
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28
29 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
30 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
31 import org.apache.tinkerpop.gremlin.structure.Direction;
32 import org.apache.tinkerpop.gremlin.structure.Edge;
33 import org.apache.tinkerpop.gremlin.structure.Vertex;
34
35 import org.openecomp.aai.db.props.AAIProperties;
36 import org.openecomp.aai.dbmodel.DbEdgeRules;
37 import org.openecomp.aai.exceptions.AAIException;
38 import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
39 import com.google.common.collect.ArrayListMultimap;
40 import com.google.common.collect.Multimap;
41
42 public class EdgeRules {
43
44         private Multimap<String, String> rules = DbEdgeRules.EdgeRules;
45         private Multimap<String, String> deleteScope =  DbEdgeRules.DefaultDeleteScope;
46         private final int EDGE_NAME = 0;
47         private final int DIRECTION = 1;
48         private final int MULTIPLICITY_RULE = 2;
49         private final int IS_PARENT = 3;
50         private final int USES_RESOURCE = 4;
51         private final int HAS_DEL_TARGET = 5;
52         private final int SVC_INFRA = 6;
53         
54         /**
55          * Instantiates a new edge rules.
56          */
57         private EdgeRules() {
58         
59         }
60         private static class Helper {
61                 private static final EdgeRules INSTANCE = new EdgeRules();
62                 
63         }
64         
65         /**
66          * Gets the single instance of EdgeRules.
67          *
68          * @return single instance of EdgeRules
69          */
70         public static EdgeRules getInstance() {
71                 return Helper.INSTANCE;
72
73         }
74         
75         /**
76          * Adds the tree edge.
77          *
78          * @param aVertex the out vertex
79          * @param bVertex the in vertex
80          * @return the edge
81          * @throws AAIException the AAI exception
82          * @throws NoEdgeRuleFoundException 
83          */
84         public Edge addTreeEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
85                 return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex);
86         }
87         
88         /**
89          * Adds the edge.
90          *
91          * @param aVertex the out vertex
92          * @param bVertex the in vertex
93          * @return the edge
94          * @throws AAIException the AAI exception
95          * @throws NoEdgeRuleFoundException 
96          */
97         public Edge addEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
98                 return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex);
99         }
100         
101         /**
102          * Adds the edge.
103          *
104          * @param type the type
105          * @param aVertex the out vertex
106          * @param bVertex the in vertex
107          * @return the edge
108          * @throws AAIException the AAI exception
109          * @throws NoEdgeRuleFoundException 
110          */
111         private Edge addEdge(EdgeType type, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException, NoEdgeRuleFoundException {
112
113                 EdgeRule rule = this.getEdgeRule(type, aVertex, bVertex);
114
115                 Edge e = null;
116                 if (this.validateMultiplicity(rule, traversalSource, aVertex, bVertex)) {
117                         if (rule.getDirection().equals(Direction.OUT)) {
118                                 e = aVertex.addEdge(rule.getLabel(), bVertex);
119                         } else if (rule.getDirection().equals(Direction.IN)) {
120                                 e = bVertex.addEdge(rule.getLabel(), aVertex);
121                         }
122                         
123                         this.addProperties(e, rule);
124                 }
125                 return e;
126         }
127
128         /**
129          * Adds the properties.
130          *
131          * @param edge the edge
132          * @param rule the rule
133          */
134         public void addProperties(Edge edge, EdgeRule rule) {
135                 
136                 // In DbEdgeRules.EdgeRules -- What we have as "edgeRule" is a comma-delimited set of strings.
137                 // The first item is the edgeLabel.
138                 // The second in the list is always "direction" which is always OUT for the way we've implemented it.
139                 // Items starting at "firstTagIndex" and up are all assumed to be booleans that map according to 
140                 // tags as defined in EdgeInfoMap.
141                 // Note - if they are tagged as 'reverse', that means they get the tag name with "-REV" on it
142                 Map<String, String> propMap = rule.getEdgeProperties();
143                 
144                 for (String key : propMap.keySet()) {
145                         String revKeyname = key + "-REV";
146                         String triple = propMap.get(key);
147                         if(triple.equals("true")){
148                                 edge.property(key, true);
149                                 edge.property(revKeyname,false);
150                         } else if (triple.equals("false")) {
151                                 edge.property(key, false);
152                                 edge.property(revKeyname,false);
153                         } else if (triple.equals("reverse")) {
154                                 edge.property(key, false);
155                                 edge.property(revKeyname,true);
156                         }
157                 }
158         }
159         
160         /**
161          * Checks for edge rule.
162          *
163          * @param outType the out type
164          * @param inType the in type
165          * @return true, if successful
166          */
167         public boolean hasEdgeRule(String outType, String inType) {
168                 
169                 Collection<String> collection = rules.get(outType + "|" + inType);
170
171                 return !collection.isEmpty();
172                 
173         }
174         
175         /**
176          * Checks for edge rule.
177          *
178          * @param aVertex the out vertex
179          * @param bVertex the in vertex
180          * @return true, if successful
181          */
182         public boolean hasEdgeRule(Vertex aVertex, Vertex bVertex) {
183                 String outType = (String)aVertex.<String>property("aai-node-type").orElse(null);
184                 String inType = (String)bVertex.<String>property("aai-node-type").orElse(null);
185                 
186                 return this.hasEdgeRule(outType, inType);
187                 
188         }
189         
190         public Map<String, EdgeRule> getEdgeRules(String outType, String inType) throws AAIException {
191                 Map<String, EdgeRule> result = new HashMap<>();
192                 EdgeRule rule = null;
193                 for (EdgeType type : EdgeType.values()) {
194                         try {
195                                 rule = this.getEdgeRule(type, outType, inType);
196                                 result.put(rule.getLabel(), rule);
197                         } catch (NoEdgeRuleFoundException e) {
198                                 continue;
199                         }
200                 }
201                 
202                 return result;
203         }
204         /**
205          * Gets the edge rule.
206          *
207          * @param outType the out type
208          * @param inType the in type
209          * @return the edge rule
210          * @throws AAIException the AAI exception
211          */
212         public EdgeRule getEdgeRule(EdgeType type, String outType, String inType) throws AAIException {
213                 EdgeRule rule = new EdgeRule();
214                 Collection<String> collection = null;
215                 boolean isFlipped = false;
216                 if (this.hasEdgeRule(outType, inType) || this.hasEdgeRule(inType, outType)) {
217                 } else {
218                         String detail = "No EdgeRule found for passed nodeTypes: " + outType + ", " + inType + ".";
219                         throw new AAIException("AAI_6120", detail); 
220                 }
221                 String key = outType + "|" + inType;
222                 collection = rules.get(key);
223
224                 String[] info = null;
225                 Iterator<String> iterator = collection.iterator();
226                 info = this.findRuleForContext(type, key, iterator);
227                 if (info == null) { //didn't find anything in that order, look again
228                         key = inType + "|" + outType;
229                         collection = rules.get(key);
230                         iterator = collection.iterator();
231                         info = this.findRuleForContext(type, key, iterator);
232                         isFlipped = true;
233                 }
234                 if (info == null) {
235                         throw new NoEdgeRuleFoundException("No EdgeRule found for EdgeType: " + type + " and node types: " + outType + " " + inType);
236                 }
237                 rule.setLabel(info[this.EDGE_NAME]);
238                 rule.setMultiplicityRule(MultiplicityRule.valueOf(info[this.MULTIPLICITY_RULE].toUpperCase()));
239                 rule.setHasDelTarget(info[this.HAS_DEL_TARGET]);
240                 rule.setUsesResource(info[this.USES_RESOURCE]);
241                 rule.setIsParent(info[this.IS_PARENT]);
242                 rule.setServiceInfrastructure(info[this.SVC_INFRA]);
243                 Direction direction = Direction.valueOf(info[this.DIRECTION]);
244                 if (isFlipped && direction.equals(Direction.OUT)) {
245                         rule.setDirection(Direction.IN);
246                 } else if (isFlipped && direction.equals(Direction.IN)){
247                         rule.setDirection(Direction.OUT);
248                 } else {
249                         rule.setDirection(direction);
250                 }
251
252                 return rule;
253         }
254         
255         private String[] findRuleForContext (EdgeType type, String key, Iterator<String> itr) {
256                 String[] result = null;
257                 String s = "";
258                 String isParent = "";
259                 String[] info = new String[10];
260                 while (itr.hasNext()) {
261                         s = itr.next();
262                         info = s.split(",");
263                         isParent = info[this.IS_PARENT];
264                         //lazily stop iterating if we find a match
265                         //should there be a mismatch between type and isParent,
266                         //the caller will receive something.
267                         //this operates on the assumption that there are at most two rules
268                         //for a given vertex pair
269                         if (type.equals(EdgeType.TREE) && (isParent.equals("true") || isParent.equals("reverse"))) {
270                                 result = info;
271                                 break;
272                         } else if (type.equals(EdgeType.COUSIN) && isParent.equals("false")) {
273                                 result = info;
274                                 break;
275                         }
276                 }
277                 
278                 
279                 return result;
280         }
281         /**
282          * Gets the edge rule.
283          *
284          * @param aVertex the out vertex
285          * @param bVertex the in vertex
286          * @return the edge rule
287          * @throws AAIException the AAI exception
288          * @throws NoEdgeRuleFoundException 
289          */
290         public EdgeRule getEdgeRule(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException, NoEdgeRuleFoundException {
291                 String outType = (String)aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
292                 String inType = (String)bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
293                 
294                 return this.getEdgeRule(type, outType, inType);
295
296                 
297         }
298         
299         /**
300          * Gets the delete semantic.
301          *
302          * @param nodeType the node type
303          * @return the delete semantic
304          */
305         public DeleteSemantic getDeleteSemantic(String nodeType) {
306                 Collection<String> semanticCollection = deleteScope.get(nodeType);
307                 String semantic = semanticCollection.iterator().next();
308                 
309                 return DeleteSemantic.valueOf(semantic);
310                 
311         }
312         
313         /**
314          * Validate multiplicity.
315          *
316          * @param rule the rule
317          * @param aVertex the out vertex
318          * @param bVertex the in vertex
319          * @return true, if successful
320          * @throws AAIException the AAI exception
321          */
322         private boolean validateMultiplicity(EdgeRule rule, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
323
324                 if (rule.getDirection().equals(Direction.OUT)) {
325                         
326                 } else if (rule.getDirection().equals(Direction.IN)) {
327                         Vertex tempV = bVertex;
328                         bVertex = aVertex;
329                         aVertex = tempV;
330                 }
331                                 
332                 String aVertexType = aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
333                 String bVertexType =  bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
334                 String label = rule.getLabel();
335                 MultiplicityRule multiplicityRule = rule.getMultiplicityRule();
336                 List<Edge> outEdges = traversalSource.V(aVertex).outE(label).where(__.inV().has(AAIProperties.NODE_TYPE, bVertexType)).toList();
337                 List<Edge> inEdges = traversalSource.V(bVertex).inE(label).where(__.outV().has(AAIProperties.NODE_TYPE, aVertexType)).toList();
338                 String detail = "";
339                 if (multiplicityRule.equals(MultiplicityRule.ONE2ONE)) {
340                         if (inEdges.size() >= 1 || outEdges.size() >= 1 ) {
341                                 detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType;
342                         }
343                 } else if (multiplicityRule.equals(MultiplicityRule.ONE2MANY)) {
344                         if (inEdges.size() >= 1) {
345                                 detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType;
346                         }
347                 } else if (multiplicityRule.equals(MultiplicityRule.MANY2ONE)) {
348                         if (outEdges.size() >= 1) {
349                                 detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType;
350                         }
351                 } else {
352                         
353                 }
354                 
355                 if (!detail.equals("")) {
356                         throw new AAIException("AAI_6140", detail);
357                 }
358                 
359                 return true;
360                 
361         }
362         
363         public Multimap<String, EdgeRule> getAllRules() throws AAIException {
364                 
365                 Multimap<String, EdgeRule> result = ArrayListMultimap.create();
366                 
367                 for (String key : this.rules.keySet()) {
368                         String outType = "";
369                         String inType = "";
370                         String[] split = key.split("\\|");
371                         outType = split[0];
372                         inType = split[1];
373                         result.putAll(key,this.getEdgeRules(outType, inType).values());
374                 }
375                 
376                 return result;
377         }
378         
379 }