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