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