Update license files, sonar plugin and fix tests
[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 }