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