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