2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.openecomp.aai.serialization.db;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
28 import java.util.Optional;
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;
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;
44 public class EdgeRules {
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;
57 * Instantiates a new edge rules.
62 private static class Helper {
63 private static final EdgeRules INSTANCE = new EdgeRules();
68 * Gets the single instance of EdgeRules.
70 * @return single instance of EdgeRules
72 public static EdgeRules getInstance() {
73 return Helper.INSTANCE;
80 * @param aVertex the out vertex
81 * @param bVertex the in vertex
83 * @throws AAIException the AAI exception
84 * @throws NoEdgeRuleFoundException
86 public Edge addTreeEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
87 return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex, false);
93 * @param aVertex the out vertex
94 * @param bVertex the in vertex
96 * @throws AAIException the AAI exception
97 * @throws NoEdgeRuleFoundException
99 public Edge addEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
100 return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex, false);
104 * Adds the tree edge.
106 * @param aVertex the out vertex
107 * @param bVertex the in vertex
109 * @throws AAIException the AAI exception
110 * @throws NoEdgeRuleFoundException
112 public Edge addTreeEdgeIfPossible(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
113 return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex, true);
119 * @param aVertex the out vertex
120 * @param bVertex the in vertex
122 * @throws AAIException the AAI exception
123 * @throws NoEdgeRuleFoundException
125 public Edge addEdgeIfPossible(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
126 return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex, true);
132 * @param type the type
133 * @param aVertex the out vertex
134 * @param bVertex the in vertex
136 * @throws AAIException the AAI exception
137 * @throws NoEdgeRuleFoundException
139 private Edge addEdge(EdgeType type, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex, boolean isBestEffort) throws AAIException, NoEdgeRuleFoundException {
141 EdgeRule rule = this.getEdgeRule(type, aVertex, bVertex);
145 Optional<String> message = this.validateMultiplicity(rule, traversalSource, aVertex, bVertex);
147 if (message.isPresent() && !isBestEffort) {
148 throw new EdgeMultiplicityException(message.get());
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);
157 this.addProperties(e, rule);
163 * Adds the properties.
165 * @param edge the edge
166 * @param rule the rule
168 public void addProperties(Edge edge, EdgeRule rule) {
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();
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);
195 * Checks for edge rule.
197 * @param outType the out type
198 * @param inType the in type
199 * @return true, if successful
201 public boolean hasEdgeRule(String outType, String inType) {
203 Collection<String> collection = rules.get(outType + "|" + inType);
205 return !collection.isEmpty();
210 * Checks for edge rule.
212 * @param aVertex the out vertex
213 * @param bVertex the in vertex
214 * @return true, if successful
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);
220 return this.hasEdgeRule(outType, inType);
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()) {
229 rule = this.getEdgeRule(type, outType, inType);
230 result.put(rule.getLabel(), rule);
231 } catch (NoEdgeRuleFoundException e) {
239 * Gets the edge rule.
241 * @param outType the out type
242 * @param inType the in type
243 * @return the edge rule
244 * @throws AAIException the AAI exception
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)) {
252 String detail = "No EdgeRule found for passed nodeTypes: " + outType + ", " + inType + ".";
253 throw new AAIException("AAI_6120", detail);
255 String key = outType + "|" + inType;
256 collection = rules.get(key);
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);
269 throw new NoEdgeRuleFoundException("No EdgeRule found for EdgeType: " + type + " and node types: " + outType + " " + inType);
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);
283 rule.setDirection(direction);
289 private String[] findRuleForContext (EdgeType type, String key, Iterator<String> itr) {
290 String[] result = null;
292 String isParent = "";
293 String[] info = new String[10];
294 while (itr.hasNext()) {
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"))) {
306 } else if (type.equals(EdgeType.COUSIN) && isParent.equals("false")) {
316 * Gets the edge rule.
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
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);
328 return this.getEdgeRule(type, outType, inType);
334 * Gets the delete semantic.
336 * @param nodeType the node type
337 * @return the delete semantic
339 public DeleteSemantic getDeleteSemantic(String nodeType) {
340 Collection<String> semanticCollection = deleteScope.get(nodeType);
341 String semantic = semanticCollection.iterator().next();
343 return DeleteSemantic.valueOf(semantic);
348 * Validate multiplicity.
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
356 private Optional<String> validateMultiplicity(EdgeRule rule, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) {
358 if (rule.getDirection().equals(Direction.OUT)) {
360 } else if (rule.getDirection().equals(Direction.IN)) {
361 Vertex tempV = bVertex;
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();
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;
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;
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;
389 if (!detail.equals("")) {
390 return Optional.of(detail);
392 return Optional.empty();
398 public Multimap<String, EdgeRule> getAllRules() throws AAIException {
400 Multimap<String, EdgeRule> result = ArrayListMultimap.create();
402 for (String key : this.rules.keySet()) {
405 String[] split = key.split("\\|");
408 result.putAll(key,this.getEdgeRules(outType, inType).values());