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;
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;
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;
42 public class EdgeRules {
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;
55 * Instantiates a new edge rules.
60 private static class Helper {
61 private static final EdgeRules INSTANCE = new EdgeRules();
66 * Gets the single instance of EdgeRules.
68 * @return single instance of EdgeRules
70 public static EdgeRules getInstance() {
71 return Helper.INSTANCE;
78 * @param aVertex the out vertex
79 * @param bVertex the in vertex
81 * @throws AAIException the AAI exception
82 * @throws NoEdgeRuleFoundException
84 public Edge addTreeEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
85 return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex);
91 * @param aVertex the out vertex
92 * @param bVertex the in vertex
94 * @throws AAIException the AAI exception
95 * @throws NoEdgeRuleFoundException
97 public Edge addEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
98 return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex);
104 * @param type the type
105 * @param aVertex the out vertex
106 * @param bVertex the in vertex
108 * @throws AAIException the AAI exception
109 * @throws NoEdgeRuleFoundException
111 private Edge addEdge(EdgeType type, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException, NoEdgeRuleFoundException {
113 EdgeRule rule = this.getEdgeRule(type, aVertex, bVertex);
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);
123 this.addProperties(e, rule);
129 * Adds the properties.
131 * @param edge the edge
132 * @param rule the rule
134 public void addProperties(Edge edge, EdgeRule rule) {
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();
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);
161 * Checks for edge rule.
163 * @param outType the out type
164 * @param inType the in type
165 * @return true, if successful
167 public boolean hasEdgeRule(String outType, String inType) {
169 Collection<String> collection = rules.get(outType + "|" + inType);
171 return !collection.isEmpty();
176 * Checks for edge rule.
178 * @param aVertex the out vertex
179 * @param bVertex the in vertex
180 * @return true, if successful
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);
186 return this.hasEdgeRule(outType, inType);
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()) {
195 rule = this.getEdgeRule(type, outType, inType);
196 result.put(rule.getLabel(), rule);
197 } catch (NoEdgeRuleFoundException e) {
205 * Gets the edge rule.
207 * @param outType the out type
208 * @param inType the in type
209 * @return the edge rule
210 * @throws AAIException the AAI exception
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)) {
218 String detail = "No EdgeRule found for passed nodeTypes: " + outType + ", " + inType + ".";
219 throw new AAIException("AAI_6120", detail);
221 String key = outType + "|" + inType;
222 collection = rules.get(key);
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);
235 throw new NoEdgeRuleFoundException("No EdgeRule found for EdgeType: " + type + " and node types: " + outType + " " + inType);
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);
249 rule.setDirection(direction);
255 private String[] findRuleForContext (EdgeType type, String key, Iterator<String> itr) {
256 String[] result = null;
258 String isParent = "";
259 String[] info = new String[10];
260 while (itr.hasNext()) {
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"))) {
272 } else if (type.equals(EdgeType.COUSIN) && isParent.equals("false")) {
282 * Gets the edge rule.
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
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);
294 return this.getEdgeRule(type, outType, inType);
300 * Gets the delete semantic.
302 * @param nodeType the node type
303 * @return the delete semantic
305 public DeleteSemantic getDeleteSemantic(String nodeType) {
306 Collection<String> semanticCollection = deleteScope.get(nodeType);
307 String semantic = semanticCollection.iterator().next();
309 return DeleteSemantic.valueOf(semantic);
314 * Validate multiplicity.
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
322 private boolean validateMultiplicity(EdgeRule rule, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
324 if (rule.getDirection().equals(Direction.OUT)) {
326 } else if (rule.getDirection().equals(Direction.IN)) {
327 Vertex tempV = bVertex;
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();
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;
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;
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;
355 if (!detail.equals("")) {
356 throw new AAIException("AAI_6140", detail);
363 public Multimap<String, EdgeRule> getAllRules() throws AAIException {
365 Multimap<String, EdgeRule> result = ArrayListMultimap.create();
367 for (String key : this.rules.keySet()) {
370 String[] split = key.split("\\|");
373 result.putAll(key,this.getEdgeRules(outType, inType).values());