re base code
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / operations / impl / DefaultDerivedFromOperation.java
index 2e5da8d..6f95558 100644 (file)
@@ -1,25 +1,29 @@
 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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.openecomp.sdc.common.log.wrappers.Logger;
 import org.springframework.stereotype.Component;
 
-import fj.data.Either;
+import java.util.*;
+import java.util.function.Function;
 
 @Component
 public class DefaultDerivedFromOperation implements DerivedFromOperation {
 
-    private static final Logger log = LoggerFactory.getLogger(DefaultDerivedFromOperation.class);
+    private static final Logger log = Logger.getLogger(DefaultDerivedFromOperation.class.getName());
     private TitanGenericDao titanGenericDao;
 
     public DefaultDerivedFromOperation(TitanGenericDao titanGenericDao) {
@@ -28,8 +32,8 @@ public class DefaultDerivedFromOperation implements DerivedFromOperation {
 
     @Override
     public Either<GraphRelation, StorageOperationStatus> addDerivedFromRelation(String parentUniqueId, String derivedFromUniqueId, NodeTypeEnum nodeType) {
-        UniqueIdData from = new UniqueIdData(NodeTypeEnum.PolicyType, parentUniqueId);
-        UniqueIdData to = new UniqueIdData(NodeTypeEnum.PolicyType, derivedFromUniqueId);
+        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);
@@ -45,8 +49,8 @@ public class DefaultDerivedFromOperation implements DerivedFromOperation {
 
     @Override
     public StorageOperationStatus removeDerivedFromRelation(String uniqueId, String derivedFromUniqueId, NodeTypeEnum nodeType) {
-        UniqueIdData from = new UniqueIdData(NodeTypeEnum.PolicyType, uniqueId);
-        UniqueIdData to = new UniqueIdData(NodeTypeEnum.PolicyType, derivedFromUniqueId);
+        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);
@@ -63,6 +67,90 @@ public class DefaultDerivedFromOperation implements DerivedFromOperation {
     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;
+    }
 
 }