c207965b46e4a39fd5b334b3b0bc17069e7ffc6b
[sdc.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2019 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.sdc.be.model.operations.impl;
22
23 import fj.data.Either;
24 import org.apache.commons.lang3.tuple.ImmutablePair;
25 import org.apache.commons.lang3.tuple.Pair;
26 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
27 import org.openecomp.sdc.be.dao.graph.datatype.GraphNode;
28 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
29 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao;
30 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
31 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
32 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
33 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
34 import org.openecomp.sdc.be.model.operations.api.DerivedFromOperation;
35 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
36 import org.openecomp.sdc.be.resources.data.UniqueIdData;
37 import org.openecomp.sdc.common.log.wrappers.Logger;
38 import org.springframework.beans.factory.annotation.Autowired;
39 import org.springframework.stereotype.Component;
40
41 import java.util.*;
42 import java.util.function.Function;
43
44 @Component
45 public class DefaultDerivedFromOperation implements DerivedFromOperation {
46
47     private static final Logger log = Logger.getLogger(DefaultDerivedFromOperation.class.getName());
48     private JanusGraphGenericDao janusGraphGenericDao;
49
50     @Autowired
51     public DefaultDerivedFromOperation(JanusGraphGenericDao janusGraphGenericDao) {
52         this.janusGraphGenericDao = janusGraphGenericDao;
53     }
54
55     @Override
56     public Either<GraphRelation, StorageOperationStatus> addDerivedFromRelation(String parentUniqueId, String derivedFromUniqueId, NodeTypeEnum nodeType) {
57         UniqueIdData from = new UniqueIdData(nodeType, parentUniqueId);
58         UniqueIdData to = new UniqueIdData(nodeType, derivedFromUniqueId);
59         return janusGraphGenericDao.createRelation(from, to, GraphEdgeLabels.DERIVED_FROM, null)
60                 .right()
61                 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
62     }
63
64     @Override
65     public <T extends GraphNode> Either<T, StorageOperationStatus> getDerivedFromChild(String uniqueId, NodeTypeEnum nodeType, Class<T> clazz) {
66         log.debug("#getDerivedFromChild - fetching derived from entity for node type {} with id {}", nodeType, uniqueId);
67         return janusGraphGenericDao
68             .getChild(UniqueIdBuilder.getKeyByNodeType(nodeType), uniqueId, GraphEdgeLabels.DERIVED_FROM, nodeType, clazz)
69                 .bimap(Pair::getKey,
70                        DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
71     }
72
73     @Override
74     public StorageOperationStatus removeDerivedFromRelation(String uniqueId, String derivedFromUniqueId, NodeTypeEnum nodeType) {
75         UniqueIdData from = new UniqueIdData(nodeType, uniqueId);
76         UniqueIdData to = new UniqueIdData(nodeType, derivedFromUniqueId);
77         return isDerivedFromExists(from, to)
78                 .either(isRelationExist -> isRelationExist ? deleteDerivedFrom(from, to) : StorageOperationStatus.OK,
79                         DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
80
81
82     }
83
84     private StorageOperationStatus deleteDerivedFrom(UniqueIdData from,  UniqueIdData to) {
85         return janusGraphGenericDao.deleteRelation(from, to, GraphEdgeLabels.DERIVED_FROM)
86                 .either(deletedRelation -> StorageOperationStatus.OK,
87                         DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
88     }
89
90     private Either<Boolean, JanusGraphOperationStatus> isDerivedFromExists(UniqueIdData from, UniqueIdData to) {
91         return janusGraphGenericDao.isRelationExist(from, to, GraphEdgeLabels.DERIVED_FROM);
92     }
93     
94     @Override
95     public <T extends GraphNode> Either<Boolean, StorageOperationStatus> isTypeDerivedFrom(String childCandidateType, String parentCandidateType, String currentChildType, 
96                                                                                                     NodeTypeEnum nodeType, Class<T> clazz, Function<T, String> typeProvider) {
97         Map<String, Object> propertiesToMatch = new HashMap<>();
98         propertiesToMatch.put(GraphPropertiesDictionary.TYPE.getProperty(), childCandidateType);
99         
100         Either<List<T>, JanusGraphOperationStatus> getResponse = janusGraphGenericDao
101             .getByCriteria(nodeType, propertiesToMatch, clazz);
102         if (getResponse.isRight()) {
103             JanusGraphOperationStatus janusGraphOperationStatus = getResponse.right().value();
104             log.debug("Couldn't fetch type {}, error: {}", childCandidateType,
105                 janusGraphOperationStatus);
106             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(
107                 janusGraphOperationStatus));
108         }
109         T node = getResponse.left().value().get(0);
110         String childUniqueId = node.getUniqueId();
111         String childType = typeProvider.apply(node);
112         
113         Set<String> travelledTypes = new HashSet<>();
114         if (currentChildType != null) {
115             travelledTypes.add(currentChildType);
116         }
117         
118         do {
119             travelledTypes.add(childType);
120             Either<List<ImmutablePair<T, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao
121                 .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(nodeType), childUniqueId, GraphEdgeLabels.DERIVED_FROM,
122                     nodeType, clazz);
123             if (childrenNodes.isRight()) {
124                 if (childrenNodes.right().value() != JanusGraphOperationStatus.NOT_FOUND) {
125                     JanusGraphOperationStatus janusGraphOperationStatus = getResponse.right().value();
126                     log.debug("Couldn't fetch derived from node for type {}, error: {}", childCandidateType,
127                         janusGraphOperationStatus);
128                     return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(
129                         janusGraphOperationStatus));
130                 } else {
131                     log.debug("Derived from node is not found for type {} - this is OK for root capability.", childCandidateType);
132                     return Either.left(false);
133                 }
134             }
135             String derivedFromUniqueId = childrenNodes.left().value().get(0).getLeft().getUniqueId();
136             String derivedFromType = typeProvider.apply(childrenNodes.left().value().get(0).getLeft());
137             if (derivedFromType.equals(parentCandidateType)) {
138                 log.debug("Verified that type {} derives from type {}", childCandidateType, parentCandidateType);
139                 return Either.left(true);
140             }
141             childUniqueId = derivedFromUniqueId;
142             childType = derivedFromType;
143         } while (!travelledTypes.contains(childType));
144         // this stop condition should never be used, if we use it, we have an
145         // illegal cycle in graph - "derived from" hierarchy cannot be cycled.
146         // It's here just to avoid infinite loop in case we have such cycle.
147         log.error("Detected a cycle of \"derived from\" edges starting at type node {}", childType);
148         return Either.right(StorageOperationStatus.GENERAL_ERROR);
149     }
150     
151     
152     
153     @Override
154     public <T extends GraphNode> StorageOperationStatus isUpdateParentAllowed(String oldTypeParent, String newTypeParent, String childType,
155                                                                               NodeTypeEnum nodeType, Class<T> clazz,
156                                                                               Function<T, String> typeProvider) {
157         StorageOperationStatus status;
158         if (oldTypeParent != null) {
159             
160             Either<Boolean, StorageOperationStatus> result = isTypeDerivedFrom(newTypeParent, oldTypeParent, childType, nodeType, clazz, typeProvider);
161             if (result.isRight()) {
162                 log.debug("#isUpdateParentAllowed - failed to detect that new parent {} is derived from the current parent {}",  newTypeParent, oldTypeParent);
163                 status = result.right().value();
164             }
165             else {
166                 if (result.left().value()) {
167                     log.debug("#isUpdateParentAllowed - update is allowed since new parent {} is derived from the current parent {}",  newTypeParent, oldTypeParent);
168                     status = StorageOperationStatus.OK;
169                 }
170                 else {
171                     log.debug("#isUpdateParentAllowed - update is not allowed since new parent {} is not derived from the current parent {}",  newTypeParent, oldTypeParent);
172                     status = StorageOperationStatus.CANNOT_UPDATE_EXISTING_ENTITY;
173                 }
174             }
175                         
176         }
177         else {
178             log.debug("#isUpdateParentAllowed - the update is allowed since the parent still has been not set." );
179             status = StorageOperationStatus.OK;
180         }
181         
182         return status;
183     }
184
185 }