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