Integrate aai-schema-ingest library into aai-core
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / serialization / db / EdgeSerializer.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 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 package org.onap.aai.serialization.db;
21
22 import java.util.EnumMap;
23 import java.util.Map;
24 import java.util.Optional;
25 import java.util.UUID;
26 import java.util.Map.Entry;
27
28 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
29 import org.apache.tinkerpop.gremlin.structure.Direction;
30 import org.apache.tinkerpop.gremlin.structure.Edge;
31 import org.apache.tinkerpop.gremlin.structure.Vertex;
32 import org.onap.aai.db.props.AAIProperties;
33 import org.onap.aai.edges.EdgeIngestor;
34 import org.onap.aai.edges.EdgeRule;
35 import org.onap.aai.edges.EdgeRuleQuery;
36 import org.onap.aai.edges.enums.EdgeField;
37 import org.onap.aai.edges.enums.EdgeProperty;
38 import org.onap.aai.edges.enums.EdgeType;
39 import org.onap.aai.edges.enums.MultiplicityRule;
40 import org.onap.aai.edges.exceptions.AmbiguousRuleChoiceException;
41 import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
42 import org.onap.aai.exceptions.AAIException;
43 import org.onap.aai.serialization.db.exceptions.EdgeMultiplicityException;
44 import org.onap.aai.serialization.db.exceptions.MultipleEdgeRuleFoundException;
45 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
46 import org.springframework.beans.factory.annotation.Autowired;
47 import org.springframework.stereotype.Component;
48
49 @Component
50 public class EdgeSerializer {
51
52         @Autowired
53         private EdgeIngestor edgerules;
54         
55         public EdgeSerializer(EdgeIngestor ei) {
56                 this.edgerules = ei;
57         }
58         
59         /**
60          * Adds the tree edge.
61          *
62          * @param aVertex the out vertex
63          * @param bVertex the in vertex
64          * @return the edge
65          * @throws AAIException the AAI exception
66          */
67         public Edge addTreeEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
68                 return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex, false, null);
69         }
70
71         /**
72          * Adds the edge.
73          *
74          * @param aVertex the out vertex
75          * @param bVertex the in vertex
76          * @return the edge
77          * @throws AAIException the AAI exception
78          */
79         public Edge addEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
80                 return this.addEdge(traversalSource, aVertex, bVertex, null);
81         }
82
83         public Edge addEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
84                 return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex, false, label);
85         }
86
87         public Edge addPrivateEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex, String label) throws AAIException, EdgeRuleNotFoundException, AmbiguousRuleChoiceException {
88                 return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex, false, label, true);
89         }
90
91         private Edge addEdge(EdgeType type, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex, boolean isBestEffort, String label, boolean isPrivateEdge) throws AAIException, EdgeRuleNotFoundException, AmbiguousRuleChoiceException {
92
93                 EdgeRule rule = null;
94
95                 String aType = aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
96                 String bType = bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
97                 EdgeRuleQuery edgeQuery = new EdgeRuleQuery.Builder(aType, bType).label(label).setPrivate(isPrivateEdge).build();
98
99                 rule = edgerules.getRule(edgeQuery);
100
101                 if(rule.isPrivateEdge() != isPrivateEdge){
102                         return null;
103                 }
104
105                 Edge e = null;
106
107                 Optional<String> message = this.validateMultiplicity(rule, traversalSource, aVertex, bVertex);
108
109                 if (message.isPresent() && !isBestEffort) {
110                         throw new EdgeMultiplicityException(message.get());
111                 }
112                 if (!message.isPresent()) {
113                         if (rule.getDirection().equals(Direction.OUT)) {
114                                 e = aVertex.addEdge(rule.getLabel(), bVertex);
115                         } else if (rule.getDirection().equals(Direction.IN)) {
116                                 e = bVertex.addEdge(rule.getLabel(), aVertex);
117                         }
118
119                         this.addProperties(e, rule);
120                 }
121                 return e;
122         }
123
124         /**
125          * Adds the tree edge.
126          *
127          * @param aVertex the out vertex
128          * @param bVertex the in vertex
129          * @return the edge
130          * @throws AAIException the AAI exception
131          */
132         public Edge addTreeEdgeIfPossible(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
133                 return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex, true, null);
134         }
135
136         /**
137          * Adds the edge.
138          *
139          * @param aVertex the out vertex
140          * @param bVertex the in vertex
141          * @return the edge
142          * @throws AAIException the AAI exception
143          */
144         public Edge addEdgeIfPossible(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
145                 return this.addEdgeIfPossible(traversalSource, aVertex, bVertex, null);
146         }
147         
148         public Edge addEdgeIfPossible(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
149                 return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex, true, label);
150         }
151
152         /**
153          * Adds the edge.
154          *
155          * @param type the type
156          * @param aVertex the out vertex
157          * @param bVertex the in vertex
158          * @return the edge
159          * @throws AAIException the AAI exception
160          */
161         private Edge addEdge(EdgeType type, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex, boolean isBestEffort, String label) throws AAIException {
162                 String aNodeType = (String)aVertex.property(AAIProperties.NODE_TYPE).value();
163                 String bNodeType = (String)bVertex.property(AAIProperties.NODE_TYPE).value();
164                 EdgeRuleQuery q = new EdgeRuleQuery.Builder(aNodeType, bNodeType).label(label).edgeType(type).build();
165                 EdgeRule rule;
166                 try {
167                         rule = edgerules.getRule(q);
168                 } catch (EdgeRuleNotFoundException e1) {
169                         throw new NoEdgeRuleFoundException(e1);
170                 } catch (AmbiguousRuleChoiceException e1) {
171                         throw new MultipleEdgeRuleFoundException(e1);
172                 }
173
174                 Edge e = null;
175
176                 Optional<String> message = this.validateMultiplicity(rule, traversalSource, aVertex, bVertex);
177
178                 if (message.isPresent() && !isBestEffort) {
179                         throw new EdgeMultiplicityException(message.get());
180                 }
181                 if (!message.isPresent()) {
182                         if (rule.getDirection().equals(Direction.OUT)) {
183                                 e = aVertex.addEdge(rule.getLabel(), bVertex);
184                         } else if (rule.getDirection().equals(Direction.IN)) {
185                                 e = bVertex.addEdge(rule.getLabel(), aVertex);
186                         }
187
188                         this.addProperties(e, rule);
189                 }
190                 return e;
191         }
192         
193         /**
194          * Adds the properties.
195          *
196          * @param edge the edge
197          * @param rule the rule
198          */
199         public void addProperties(Edge edge, EdgeRule rule) {
200                 Map<EdgeProperty, String> propMap = new EnumMap<>(EdgeProperty.class);
201                 propMap.put(EdgeProperty.CONTAINS, rule.getContains());
202                 propMap.put(EdgeProperty.DELETE_OTHER_V, rule.getDeleteOtherV());
203                 propMap.put(EdgeProperty.PREVENT_DELETE, rule.getPreventDelete());
204
205                 for (Entry<EdgeProperty, String> entry : propMap.entrySet()) {
206                         edge.property(entry.getKey().toString(), entry.getValue());
207                 }
208
209                 edge.property(EdgeField.PRIVATE.toString(), rule.isPrivateEdge());
210                 edge.property(AAIProperties.AAI_UUID, UUID.randomUUID().toString());
211         }
212         
213         /**
214          * Validate multiplicity.
215          *
216          * @param rule the rule
217          * @param aVertex the out vertex
218          * @param bVertex the in vertex
219          * @return true, if successful
220          * @throws AAIException the AAI exception
221          */
222         private Optional<String> validateMultiplicity(EdgeRule rule, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) {
223
224                 Vertex a = aVertex;
225                 Vertex b = bVertex;
226
227                 if (rule.getDirection().equals(Direction.OUT)) {
228                         a = aVertex;
229                         b = bVertex;
230                 } else if (rule.getDirection().equals(Direction.IN)) {
231                         a = bVertex;
232                         b = aVertex;
233                 }
234
235                 String aVertexType = a.<String>property(AAIProperties.NODE_TYPE).orElse(null);
236                 String bVertexType =  b.<String>property(AAIProperties.NODE_TYPE).orElse(null);
237                 String label = rule.getLabel();
238
239                 MultiplicityRule multiplicityRule = rule.getMultiplicityRule();
240
241                 String detail = "";
242                 final String msg = "multiplicity rule violated: only one edge can exist with label: ";
243
244                 if (multiplicityRule.equals(MultiplicityRule.ONE2ONE)) {
245                         Long outEdgesCnt = traversalSource.V(a).out(label).has(AAIProperties.NODE_TYPE, bVertexType).count().next();
246                         Long inEdgesCnt = traversalSource.V(b).in(label).has(AAIProperties.NODE_TYPE, aVertexType).count().next();
247                         if (aVertexType.equals(bVertexType)) {
248                                 inEdgesCnt = inEdgesCnt + traversalSource.V(a).in(label).has(AAIProperties.NODE_TYPE, aVertexType).count().next();
249                                 outEdgesCnt = outEdgesCnt + traversalSource.V(b).out(label).has(AAIProperties.NODE_TYPE, bVertexType).count().next();
250                         }
251                         if ( (inEdgesCnt != 0) || (outEdgesCnt != 0) ) {
252                                 detail = msg + label + " between " + aVertexType + " and " + bVertexType;
253                         }
254                 } else if (multiplicityRule.equals(MultiplicityRule.ONE2MANY)) {
255                         Long inEdgesCnt = traversalSource.V(b).in(label).has(AAIProperties.NODE_TYPE, aVertexType).count().next();
256                         if (inEdgesCnt != 0) {
257                                 detail = msg + label + " between " + aVertexType + " and " + bVertexType;
258                         }
259                 } else if (multiplicityRule.equals(MultiplicityRule.MANY2ONE)) {
260                         Long outEdgesCnt = traversalSource.V(a).out(label).has(AAIProperties.NODE_TYPE, bVertexType).count().next();
261                         if (outEdgesCnt != 0) {
262                                 detail = msg + label + " between " + aVertexType + " and " + bVertexType;
263                         }
264                 }
265
266                 if (!"".equals(detail)) {
267                         return Optional.of(detail);
268                 } else  {
269                         return Optional.empty();
270                 }
271         }
272 }