aboutsummaryrefslogtreecommitdiffstats
path: root/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DefaultDerivedFromOperation.java
blob: 6f9555899b9b8ed54709fb212d478d0a99e60a17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package org.openecomp.sdc.be.model.operations.impl;

import fj.data.Either;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
import org.openecomp.sdc.be.dao.graph.datatype.GraphNode;
import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
import org.openecomp.sdc.be.dao.titan.TitanGenericDao;
import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
import org.openecomp.sdc.be.model.operations.api.DerivedFromOperation;
import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
import org.openecomp.sdc.be.resources.data.UniqueIdData;
import org.openecomp.sdc.common.log.wrappers.Logger;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.function.Function;

@Component
public class DefaultDerivedFromOperation implements DerivedFromOperation {

    private static final Logger log = Logger.getLogger(DefaultDerivedFromOperation.class.getName());
    private TitanGenericDao titanGenericDao;

    public DefaultDerivedFromOperation(TitanGenericDao titanGenericDao) {
        this.titanGenericDao = titanGenericDao;
    }

    @Override
    public Either<GraphRelation, StorageOperationStatus> addDerivedFromRelation(String parentUniqueId, String derivedFromUniqueId, NodeTypeEnum nodeType) {
        UniqueIdData from = new UniqueIdData(nodeType, parentUniqueId);
        UniqueIdData to = new UniqueIdData(nodeType, derivedFromUniqueId);
        return titanGenericDao.createRelation(from, to, GraphEdgeLabels.DERIVED_FROM, null)
                .right()
                .map(DaoStatusConverter::convertTitanStatusToStorageStatus);
    }

    @Override
    public <T extends GraphNode> Either<T, StorageOperationStatus> getDerivedFromChild(String uniqueId, NodeTypeEnum nodeType, Class<T> clazz) {
        log.debug("#getDerivedFromChild - fetching derived from entity for node type {} with id {}", nodeType, uniqueId);
        return titanGenericDao.getChild(UniqueIdBuilder.getKeyByNodeType(nodeType), uniqueId, GraphEdgeLabels.DERIVED_FROM, nodeType, clazz)
                .bimap(Pair::getKey,
                       DaoStatusConverter::convertTitanStatusToStorageStatus);
    }

    @Override
    public StorageOperationStatus removeDerivedFromRelation(String uniqueId, String derivedFromUniqueId, NodeTypeEnum nodeType) {
        UniqueIdData from = new UniqueIdData(nodeType, uniqueId);
        UniqueIdData to = new UniqueIdData(nodeType, derivedFromUniqueId);
        return isDerivedFromExists(from, to)
                .either(isRelationExist -> isRelationExist ? deleteDerivedFrom(from, to) : StorageOperationStatus.OK,
                        DaoStatusConverter::convertTitanStatusToStorageStatus);


    }

    private StorageOperationStatus deleteDerivedFrom(UniqueIdData from,  UniqueIdData to) {
        return titanGenericDao.deleteRelation(from, to, GraphEdgeLabels.DERIVED_FROM)
                .either(deletedRelation -> StorageOperationStatus.OK,
                        DaoStatusConverter::convertTitanStatusToStorageStatus);
    }

    private Either<Boolean, TitanOperationStatus> isDerivedFromExists(UniqueIdData from, UniqueIdData to) {
        return titanGenericDao.isRelationExist(from, to, GraphEdgeLabels.DERIVED_FROM);
    }
    
    @Override
    public <T extends GraphNode> Either<Boolean, StorageOperationStatus> isTypeDerivedFrom(String childCandidateType, String parentCandidateType, String currentChildType, 
                                                                                                    NodeTypeEnum nodeType, Class<T> clazz, Function<T, String> typeProvider) {
        Map<String, Object> propertiesToMatch = new HashMap<>();
        propertiesToMatch.put(GraphPropertiesDictionary.TYPE.getProperty(), childCandidateType);
        
        Either<List<T>, TitanOperationStatus> getResponse = titanGenericDao.getByCriteria(nodeType, propertiesToMatch, clazz);
        if (getResponse.isRight()) {
            TitanOperationStatus titanOperationStatus = getResponse.right().value();
            log.debug("Couldn't fetch type {}, error: {}", childCandidateType, titanOperationStatus);
            return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(titanOperationStatus));
        }
        T node = getResponse.left().value().get(0);
        String childUniqueId = node.getUniqueId();
        String childType = typeProvider.apply(node);
        
        Set<String> travelledTypes = new HashSet<>();
        if (currentChildType != null) {
            travelledTypes.add(currentChildType);
        }
        
        do {
            travelledTypes.add(childType);
            Either<List<ImmutablePair<T, GraphEdge>>, TitanOperationStatus> childrenNodes = titanGenericDao.getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(nodeType), childUniqueId, GraphEdgeLabels.DERIVED_FROM,
                    nodeType, clazz);
            if (childrenNodes.isRight()) {
                if (childrenNodes.right().value() != TitanOperationStatus.NOT_FOUND) {
                    TitanOperationStatus titanOperationStatus = getResponse.right().value();
                    log.debug("Couldn't fetch derived from node for type {}, error: {}", childCandidateType, titanOperationStatus);
                    return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(titanOperationStatus));
                } else {
                    log.debug("Derived from node is not found for type {} - this is OK for root capability.", childCandidateType);
                    return Either.left(false);
                }
            }
            String derivedFromUniqueId = childrenNodes.left().value().get(0).getLeft().getUniqueId();
            String derivedFromType = typeProvider.apply(childrenNodes.left().value().get(0).getLeft());
            if (derivedFromType.equals(parentCandidateType)) {
                log.debug("Verified that type {} derives from type {}", childCandidateType, parentCandidateType);
                return Either.left(true);
            }
            childUniqueId = derivedFromUniqueId;
            childType = derivedFromType;
        } while (!travelledTypes.contains(childType));
        // this stop condition should never be used, if we use it, we have an
        // illegal cycle in graph - "derived from" hierarchy cannot be cycled.
        // It's here just to avoid infinite loop in case we have such cycle.
        log.error("Detected a cycle of \"derived from\" edges starting at type node {}", childType);
        return Either.right(StorageOperationStatus.GENERAL_ERROR);
    }
    
    
    
    @Override
    public <T extends GraphNode> StorageOperationStatus isUpdateParentAllowed(String oldTypeParent, String newTypeParent, String childType,
                                                                              NodeTypeEnum nodeType, Class<T> clazz,
                                                                              Function<T, String> typeProvider) {
        StorageOperationStatus status;
        if (oldTypeParent != null) {
            
            Either<Boolean, StorageOperationStatus> result = isTypeDerivedFrom(newTypeParent, oldTypeParent, childType, nodeType, clazz, typeProvider);
            if (result.isRight()) {
                log.debug("#isUpdateParentAllowed - failed to detect that new parent {} is derived from the current parent {}",  newTypeParent, oldTypeParent);
                status = result.right().value();
            }
            else {
                if (result.left().value()) {
                    log.debug("#isUpdateParentAllowed - update is allowed since new parent {} is derived from the current parent {}",  newTypeParent, oldTypeParent);
                    status = StorageOperationStatus.OK;
                }
                else {
                    log.debug("#isUpdateParentAllowed - update is not allowed since new parent {} is not derived from the current parent {}",  newTypeParent, oldTypeParent);
                    status = StorageOperationStatus.CANNOT_UPDATE_EXISTING_ENTITY;
                }
            }
                        
        }
        else {
            log.debug("#isUpdateParentAllowed - the update is allowed since the parent still has been not set." );
            status = StorageOperationStatus.OK;
        }
        
        return status;
    }

}