2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
20 package org.openecomp.sdc.be.model.operations.impl;
22 import fj.data.Either;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
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;
47 public class DefaultDerivedFromOperation implements DerivedFromOperation {
49 private static final Logger log = Logger.getLogger(DefaultDerivedFromOperation.class.getName());
50 private JanusGraphGenericDao janusGraphGenericDao;
53 public DefaultDerivedFromOperation(JanusGraphGenericDao janusGraphGenericDao) {
54 this.janusGraphGenericDao = janusGraphGenericDao;
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);
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);
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);
81 private StorageOperationStatus deleteDerivedFrom(UniqueIdData from, UniqueIdData to) {
82 return janusGraphGenericDao.deleteRelation(from, to, GraphEdgeLabels.DERIVED_FROM)
83 .either(deletedRelation -> StorageOperationStatus.OK, DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
86 private Either<Boolean, JanusGraphOperationStatus> isDerivedFromExists(UniqueIdData from, UniqueIdData to) {
87 return janusGraphGenericDao.isRelationExist(from, to, GraphEdgeLabels.DERIVED_FROM);
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));
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);
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));
119 log.debug("Derived from node is not found for type {} - this is OK for root capability.", childCandidateType);
120 return Either.left(false);
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);
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
134 // illegal cycle in graph - "derived from" hierarchy cannot be cycled.
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);
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,
149 if (result.isRight()) {
150 log.debug("#isUpdateParentAllowed - failed to detect that new parent {} is derived from the current parent {}", newTypeParent,
152 status = result.right().value();
154 if (result.left().value()) {
155 log.debug("#isUpdateParentAllowed - update is allowed since new parent {} is derived from the current parent {}", newTypeParent,
157 status = StorageOperationStatus.OK;
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;
165 log.debug("#isUpdateParentAllowed - the update is allowed since the parent still has been not set.");
166 status = StorageOperationStatus.OK;