Error re-importing VSP 88/124288/4
authorKrupaNagabhushan <krupa.nagabhushan@est.tech>
Thu, 2 Sep 2021 12:15:51 +0000 (13:15 +0100)
committerMichael Morris <michael.morris@est.tech>
Mon, 20 Sep 2021 13:35:20 +0000 (13:35 +0000)
Issue-ID: SDC-3728
Signed-off-by: KrupaNagabhushan <krupa.nagabhushan@est.tech>
Signed-off-by: André Schmid <andre.schmid@est.tech>
Change-Id: I22d6186b8e6922511a7ede584d009cfae041fabd

19 files changed:
catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/UndoCheckoutTransition.java
catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ArchiveEndpointTest.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/exception/JanusGraphException.java [new file with mode: 0644]
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/cassandra/ToscaModelImportCassandraDao.java
catalog-dao/src/main/java/org/openecomp/sdc/be/dao/janusgraph/JanusGraphGenericDao.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementLifecycleOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/OperationException.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelElementOperation.java [new file with mode: 0644]
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/PolicyTypeOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/PropertyOperation.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperationTest.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelElementOperationTest.java [new file with mode: 0644]
catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/PropertyOperationTest.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ToscaElementLifecycleOperationTest.java
common-be/src/main/java/org/openecomp/sdc/be/exception/BusinessException.java

index 4f5374f..9d3204b 100644 (file)
@@ -2595,4 +2595,20 @@ errors:
         code: 400,
         message: "Invalid label name. Only the following characters are allowed in label name: '%1'",
         messageId: "SVC4158"
+    }
+
+    #---------SVC4159-----------------------------
+    # %1 - The model name
+    COULD_NOT_DELETE_MODEL: {
+        code: 500,
+        message: "Could not delete the model '%1'.",
+        messageId: "SVC4159"
+    }
+
+    #---------SVC4160-----------------------------
+    # %1 - The model name
+    COULD_NOT_DELETE_MODEL_ELEMENTS: {
+        code: 500,
+        message: "Could not delete the model '%1' elements.",
+        messageId: "SVC4160"
     }
\ No newline at end of file
index c8b50d2..f1ea1ee 100644 (file)
@@ -106,7 +106,7 @@ public class UndoCheckoutTransition extends LifeCycleTransition {
         Either<? extends Component, ResponseFormat> result = null;
         log.debug("start performing undo-checkout for resource {}", component.getUniqueId());
         try {
-            Either<ToscaElement, StorageOperationStatus> undoCheckoutResourceResult = lifeCycleOperation.undoCheckout(component.getUniqueId());
+            Either<ToscaElement, StorageOperationStatus> undoCheckoutResourceResult = lifeCycleOperation.undoCheckout(component.getUniqueId(), component.getModel());
             if (undoCheckoutResourceResult.isRight()) {
                 log.debug("checkout failed on graph");
                 StorageOperationStatus response = undoCheckoutResourceResult.right().value();
index 18cdb42..2de9000 100644 (file)
@@ -92,6 +92,7 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.operations.TopologyTemplateOper
 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
 import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
+import org.openecomp.sdc.be.model.operations.impl.ModelElementOperation;
 import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
 import org.openecomp.sdc.be.servlets.exception.ComponentExceptionMapper;
 import org.openecomp.sdc.be.servlets.exception.DefaultExceptionMapper;
@@ -267,6 +268,11 @@ class ArchiveEndpointTest extends JerseyTest {
             return new ModelOperation(null, null, null, null);
         }
 
+        @Bean
+        ModelElementOperation modelElementOperation() {
+            return new ModelElementOperation(null, null, null);
+        }
+
         private void initGraphForTest() {
             //Create Catalog Root
             catalogVertex = GraphTestUtils.createRootCatalogVertex(janusGraphDao);
index 30fcfac..2a71089 100644 (file)
@@ -54,7 +54,7 @@ public enum ActionStatus {
     // Model related
     MODEL_ALREADY_EXISTS, INVALID_MODEL, MODEL_IMPORTS_IS_EMPTY, COULD_NOT_READ_MODEL_IMPORTS, MODEL_NOT_FOUND, MODEL_NAME_CANNOT_BE_EMPTY,
     COMPONENT_WITH_MODEL_ALREADY_EXIST, COMPONENT_WITH_VENDOR_RELEASE_ALREADY_EXISTS, COMPONENT_WITH_VENDOR_RELEASE_ALREADY_EXISTS_IN_MODEL,
-    UNKNOWN_MODEL_TYPE,
+    UNKNOWN_MODEL_TYPE, COULD_NOT_DELETE_MODEL, COULD_NOT_DELETE_MODEL_ELEMENTS,
     // Service API URL
     INVALID_SERVICE_API_URL,
     // Property related
diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/exception/JanusGraphException.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/exception/JanusGraphException.java
new file mode 100644 (file)
index 0000000..fb37b54
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.dao.api.exception;
+
+import lombok.Getter;
+import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
+
+@Getter
+public class JanusGraphException extends RuntimeException {
+
+    private final JanusGraphOperationStatus status;
+
+    public JanusGraphException(final JanusGraphOperationStatus status, final String message) {
+        super(message);
+        this.status = status;
+    }
+}
index c250aec..d21b561 100644 (file)
@@ -122,4 +122,9 @@ public class ToscaModelImportCassandraDao extends CassandraDao {
         return toscaImportByModelAccessor.findAllByModel(modelId).all();
     }
 
+    public void deleteAllByModel(final String modelId) {
+        final List<ToscaImportByModel> allByModel = findAllByModel(modelId);
+        allByModel.forEach(toscaImportByModelMapper::delete);
+    }
+
 }
index 2116dcc..8382af5 100644 (file)
@@ -48,6 +48,7 @@ import org.janusgraph.core.JanusGraphVertexQuery;
 import org.janusgraph.core.PropertyKey;
 import org.janusgraph.graphdb.query.JanusGraphPredicate;
 import org.openecomp.sdc.be.config.ConfigurationManager;
+import org.openecomp.sdc.be.dao.api.exception.JanusGraphException;
 import org.openecomp.sdc.be.dao.graph.GraphElementFactory;
 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
 import org.openecomp.sdc.be.dao.graph.datatype.GraphElementTypeEnum;
@@ -59,6 +60,7 @@ import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 import org.openecomp.sdc.be.resources.data.GraphNodeLock;
+import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
 import org.openecomp.sdc.common.log.wrappers.Logger;
 import org.springframework.beans.factory.annotation.Qualifier;
 
@@ -1318,6 +1320,58 @@ public class JanusGraphGenericDao {
         return Either.left(immutablePairs);
     }
 
+    public <T extends GraphNode> JanusGraphOperationStatus deleteAllChildrenNodes(String key, String uniqueId, GraphEdgeLabels edgeType) {
+        final JanusGraph janusGraph = getJanusGraph();
+        final Iterable<JanusGraphVertex> vertices = janusGraph.query().has(key, uniqueId).vertices();
+        if (vertices == null || !vertices.iterator().hasNext()) {
+            return JanusGraphOperationStatus.NOT_FOUND;
+        }
+        final Vertex rootVertex = vertices.iterator().next();
+        final Iterator<Edge> outEdges = rootVertex.edges(Direction.OUT, edgeType.getProperty());
+        while (outEdges.hasNext()) {
+            final Edge edge = outEdges.next();
+            final Vertex vertexIn = edge.inVertex();
+            final Iterator<Edge> outSubEdges = vertexIn.edges(Direction.OUT);
+            while (outSubEdges.hasNext()) {
+                Edge subEdge = outSubEdges.next();
+                Vertex vertex = subEdge.inVertex();
+                Map<String, Object> properties = getProperties(vertex);
+                if (properties != null) {
+                    String label = (String) properties.get(GraphPropertiesDictionary.LABEL.getProperty());
+                    if (label.equals("property")) {
+                        vertex.remove();
+                    }
+                }
+            }
+            Map<String, Object> properties = getProperties(vertexIn);
+            if (properties != null) {
+                String label = (String) properties.get(GraphPropertiesDictionary.LABEL.getProperty());
+                GraphNode node = GraphElementFactory
+                    .createElement(label, GraphElementTypeEnum.Node, properties, GraphNode.class);
+                if (node != null) {
+                    vertexIn.remove();
+                }
+            }
+        }
+        return JanusGraphOperationStatus.OK;
+    }
+
+    /**
+     * Gets the JanusGraph instance.
+     *
+     * @return the JanusGraph instance
+     * @throws JanusGraphException when the graph was not created
+     */
+    public JanusGraph getJanusGraph() {
+        final Either<JanusGraph, JanusGraphOperationStatus> graphRes = janusGraphClient.getGraph();
+        if (graphRes.isRight()) {
+            final var errorMsg = String.format("Failed to retrieve graph. Status was '%s'", graphRes.right().value());
+            log.error(EcompLoggerErrorCode.SCHEMA_ERROR, JanusGraphGenericDao.class.getName(), errorMsg);
+            throw new JanusGraphException(graphRes.right().value(), errorMsg);
+        }
+        return graphRes.left().value();
+    }
+
     public Either<List<ImmutablePair<JanusGraphVertex, Edge>>, JanusGraphOperationStatus> getChildrenVertecies(String key, String uniqueId,
                                                                                                                GraphEdgeLabels edgeType) {
         List<ImmutablePair<JanusGraphVertex, Edge>> immutablePairs = new ArrayList<>();
index 963458b..d46d4a5 100644 (file)
@@ -60,10 +60,12 @@ import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
+import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
 import org.openecomp.sdc.be.model.DistributionStatusEnum;
 import org.openecomp.sdc.be.model.LifecycleStateEnum;
+import org.openecomp.sdc.be.model.Model;
 import org.openecomp.sdc.be.model.User;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.TopologyTemplate;
 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement;
@@ -71,10 +73,12 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElementTypeEnum;
 import org.openecomp.sdc.be.model.jsonjanusgraph.enums.JsonConstantKeysEnum;
 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
+import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
 import org.openecomp.sdc.common.jsongraph.util.CommonUtility;
 import org.openecomp.sdc.common.jsongraph.util.CommonUtility.LogLevelEnum;
 import org.openecomp.sdc.common.log.wrappers.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
 
 @org.springframework.stereotype.Component("tosca-element-lifecycle-operation")
 /**
@@ -87,6 +91,12 @@ public class ToscaElementLifecycleOperation extends BaseOperation {
     private static final String FAILED_TO_DELETE_LAST_STATE_EDGE_STATUS_IS = "Failed to delete last state edge. Status is {}. ";
     private static final String FAILED_TO_GET_VERTICES = "Failed to get vertices by id {}. Status is {}. ";
     private static final Logger log = Logger.getLogger(ToscaElementLifecycleOperation.class);
+    private final ModelOperation modelOperation;
+
+    @Autowired
+    public ToscaElementLifecycleOperation(ModelOperation modelOperation) {
+        this.modelOperation = modelOperation;
+    }
 
     static StorageOperationStatus handleFailureToPrepareParameters(final JanusGraphOperationStatus status, final String toscaElementId) {
         CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId);
@@ -223,12 +233,12 @@ public class ToscaElementLifecycleOperation extends BaseOperation {
      * @param toscaElementId
      * @return
      */
-    public Either<ToscaElement, StorageOperationStatus> undoCheckout(String toscaElementId) {
+    public Either<ToscaElement, StorageOperationStatus> undoCheckout(String toscaElementId, String model) {
         try {
             return janusGraphDao.getVertexById(toscaElementId, JsonParseFlagEnum.ParseMetadata).right().map(errorStatus -> {
                 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId);
                 return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(errorStatus);
-            }).left().bind(this::retrieveAndUpdatePreviousVersion).left().bind(this::updateEdgeToCatalogRootAndReturnPreVersionElement);
+            }).left().bind(this::retrieveAndUpdatePreviousVersion).left().bind(tuple -> updateEdgeToCatalogRootAndReturnPreVersionElement(tuple, model));
         } catch (Exception e) {
             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Exception occurred during undo checkout tosca element {}. {}", toscaElementId,
                 e.getMessage());
@@ -260,13 +270,17 @@ public class ToscaElementLifecycleOperation extends BaseOperation {
     }
 
     private Either<ToscaElement, StorageOperationStatus> updateEdgeToCatalogRootAndReturnPreVersionElement(
-        final P2<GraphVertex, JanusGraphVertex> tuple) {
+        final P2<GraphVertex, JanusGraphVertex> tuple, final String model) {
         final GraphVertex currVersionV = tuple._1();
         final JanusGraphVertex preVersionVertex = tuple._2();
         StorageOperationStatus updateCatalogRes = updateEdgeToCatalogRootByUndoCheckout(preVersionVertex, currVersionV);
         if (updateCatalogRes != StorageOperationStatus.OK) {
             return Either.right(updateCatalogRes);
         } else {
+            final Optional<Model> modelOptional = modelOperation.findModelByName(model);
+            if (modelOptional.isPresent() && modelOptional.get().getModelType() == ModelTypeEnum.NORMATIVE_EXTENSION) {
+                modelOperation.deleteModel(modelOptional.get(), false);
+            }
             final ToscaElementOperation operation = getToscaElementOperation(currVersionV.getLabel());
             return operation.deleteToscaElement(currVersionV).left().bind(discarded -> getUpdatedPreVersionElement(operation, preVersionVertex));
         }
index 30323af..7631516 100644 (file)
@@ -35,7 +35,13 @@ public class OperationException extends BusinessException {
         params = new String[0];
     }
 
-    public OperationException(final ActionStatus actionStatus, String... params) {
+    public OperationException(final ActionStatus actionStatus, final String... params) {
+        this.actionStatus = actionStatus;
+        this.params = params;
+    }
+
+    public OperationException(final Throwable cause, final ActionStatus actionStatus, final String... params) {
+        super(cause);
         this.actionStatus = actionStatus;
         this.params = params;
     }
index d6cca3f..a0963c9 100644 (file)
@@ -24,15 +24,17 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.collections4.MapUtils;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.janusgraph.core.JanusGraph;
 import org.openecomp.sdc.be.config.BeEcompErrorManager;
 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
 import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphGenericDao;
 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
+import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
+import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
-import org.openecomp.sdc.be.model.DataTypeDefinition;
 import org.openecomp.sdc.be.resources.data.DataTypeData;
 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
 import org.slf4j.Logger;
@@ -45,12 +47,16 @@ public class DataTypeOperation extends AbstractOperation {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(DataTypeOperation.class);
 
-    private final ModelOperation modelOperation;
+    private ModelOperation modelOperation;
 
     @Autowired
-    public DataTypeOperation(final HealingJanusGraphGenericDao janusGraphGenericDao,
-                             final ModelOperation modelOperation) {
+    public DataTypeOperation(final HealingJanusGraphGenericDao janusGraphGenericDao) {
         this.janusGraphGenericDao = janusGraphGenericDao;
+    }
+
+    //circular dependency ModelOperation->ModelElementOperation->DataTypeOperation
+    @Autowired
+    public void setModelOperation(final ModelOperation modelOperation) {
         this.modelOperation = modelOperation;
     }
 
@@ -132,4 +138,18 @@ public class DataTypeOperation extends AbstractOperation {
         return getDataTypes.left().value();
     }
 
+    public void deleteDataTypesByModelId(final String modelId) {
+        final JanusGraph janusGraph = janusGraphGenericDao.getJanusGraph();
+        final GraphTraversalSource traversal = janusGraph.traversal();
+        final List<Vertex> dataTypeList = traversal.V()
+            .has(GraphPropertiesDictionary.UNIQUE_ID.getProperty(), modelId)
+            .out(GraphEdgeLabels.MODEL_ELEMENT.getProperty())
+            .has(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.DataType.getName())
+            .toList();
+        dataTypeList.forEach(dataTypeVertex -> {
+            traversal.V(dataTypeVertex).out(GraphEdgeLabels.PROPERTY.getProperty()).drop().iterate();
+            dataTypeVertex.remove();
+        });
+    }
+
 }
diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelElementOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelElementOperation.java
new file mode 100644 (file)
index 0000000..048fbfd
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.model.operations.impl;
+
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao;
+import org.openecomp.sdc.be.model.Model;
+import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component("model-element-operation")
+public class ModelElementOperation {
+
+    private final JanusGraphGenericDao janusGraphGenericDao;
+    private final DataTypeOperation dataTypeOperation;
+    private final PolicyTypeOperation policyTypeOperation;
+
+    @Autowired
+    public ModelElementOperation(final JanusGraphGenericDao janusGraphGenericDao,
+                                 final DataTypeOperation dataTypeOperation,
+                                 final PolicyTypeOperation policyTypeOperation) {
+        this.janusGraphGenericDao = janusGraphGenericDao;
+        this.dataTypeOperation = dataTypeOperation;
+        this.policyTypeOperation = policyTypeOperation;
+    }
+
+    /**
+     * Deletes the given model if it exists, along with its MODEL_ELEMENT edges and import files.
+     *
+     * @param model         the model
+     * @param inTransaction if the operation is called in the middle of a janusgraph transaction
+     */
+    public void deleteModelElements(final Model model, final boolean inTransaction) {
+        boolean rollback = false;
+
+        try {
+            final String modelId = UniqueIdBuilder.buildModelUid(model.getName());
+            dataTypeOperation.deleteDataTypesByModelId(modelId);
+            policyTypeOperation.deletePolicyTypesByModelId(modelId);
+        } catch (final Exception e) {
+            rollback = true;
+            throw new OperationException(e, ActionStatus.COULD_NOT_DELETE_MODEL_ELEMENTS, model.getName());
+        } finally {
+            if (!inTransaction) {
+                if (rollback) {
+                    janusGraphGenericDao.rollback();
+                } else {
+                    janusGraphGenericDao.commit();
+                }
+            }
+        }
+    }
+
+}
index 095b4e1..b5cb9d9 100644 (file)
@@ -38,10 +38,10 @@ import org.openecomp.sdc.be.dao.api.ActionStatus;
 import org.openecomp.sdc.be.dao.cassandra.ToscaModelImportCassandraDao;
 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
+import org.openecomp.sdc.be.dao.janusgraph.JanusGraphDao;
 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao;
 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
-import org.openecomp.sdc.be.dao.janusgraph.JanusGraphDao;
 import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
 import org.openecomp.sdc.be.data.model.ToscaImportByModel;
@@ -71,6 +71,7 @@ public class ModelOperation {
     private final JanusGraphDao janusGraphDao;
     private final ToscaModelImportCassandraDao toscaModelImportCassandraDao;
     private final DerivedFromOperation derivedFromOperation;
+    private ModelElementOperation modelElementOperation;
 
     @Autowired
     public ModelOperation(final JanusGraphGenericDao janusGraphGenericDao,
@@ -322,4 +323,54 @@ public class ModelOperation {
             + "description: Auto-generated file that contains package custom types or types added after system installation." + "\n";
     }
 
+    /**
+     * Deletes the given model if it exists, along with its MODEL_ELEMENT edges and import files.
+     *
+     * @param model         the model
+     * @param inTransaction if the operation is called in the middle of a janusgraph transaction
+     */
+    public void deleteModel(final Model model, final boolean inTransaction) {
+        boolean rollback = false;
+
+        try {
+            final GraphVertex modelVertexByName = findModelVertexByName(model.getName()).orElse(null);
+            if (modelVertexByName == null) {
+                return;
+            }
+            toscaModelImportCassandraDao.deleteAllByModel(model.getName());
+            modelElementOperation.deleteModelElements(model, inTransaction);
+            deleteModel(model);
+        } catch (final OperationException e) {
+            rollback = true;
+            throw e;
+        } catch (final Exception e) {
+            rollback = true;
+            throw new OperationException(e, ActionStatus.COULD_NOT_DELETE_MODEL, model.getName());
+        } finally {
+            if (!inTransaction) {
+                if (rollback) {
+                    janusGraphGenericDao.rollback();
+                } else {
+                    janusGraphGenericDao.commit();
+                }
+            }
+        }
+    }
+
+    private void deleteModel(final Model model) {
+        final var modelData = new ModelData(model.getName(), UniqueIdBuilder.buildModelUid(model.getName()), model.getModelType());
+        final Either<ModelData, JanusGraphOperationStatus> deleteParentNodeByModel = janusGraphGenericDao.deleteNode(modelData, ModelData.class);
+        if (deleteParentNodeByModel.isRight()) {
+            final var janusGraphOperationStatus = deleteParentNodeByModel.right().value();
+            log.error(EcompLoggerErrorCode.DATA_ERROR, ModelOperation.class.getName(),
+                "Failed to delete model {} on JanusGraph with status {}", new Object[] {model.getName(), janusGraphOperationStatus});
+            throw new OperationException(ActionStatus.COULD_NOT_DELETE_MODEL, model.getName());
+        }
+    }
+
+    @Autowired
+    public void setModelElementOperation(final ModelElementOperation modelElementOperation) {
+        this.modelElementOperation = modelElementOperation;
+    }
+
 }
index 99a2841..db3c557 100644 (file)
@@ -18,8 +18,8 @@
  * ============LICENSE_END=========================================================
  */
 package org.openecomp.sdc.be.model.operations.impl;
+
 import static org.openecomp.sdc.be.dao.janusgraph.JanusGraphUtils.buildNotInPredicate;
-import static org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR;
 
 import fj.data.Either;
 import java.util.ArrayList;
@@ -31,6 +31,9 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.janusgraph.core.JanusGraph;
 import org.janusgraph.graphdb.query.JanusGraphPredicate;
 import org.openecomp.sdc.be.config.BeEcompErrorManager;
 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
@@ -60,13 +63,17 @@ public class PolicyTypeOperation extends AbstractOperation implements IPolicyTyp
     private static final Logger log = Logger.getLogger(PolicyTypeOperation.class.getName());
     private static final String CREATE_FLOW_CONTEXT = "CreatePolicyType";
     private static final String GET_FLOW_CONTEXT = "GetPolicyType";
-    @Autowired
-    private PropertyOperation propertyOperation;
-    @Autowired
-    private DerivedFromOperation derivedFromOperation;
-    @Autowired
-    private OperationUtils operationUtils;
+    private final PropertyOperation propertyOperation;
+    private final DerivedFromOperation derivedFromOperation;
+    private final OperationUtils operationUtils;
 
+    @Autowired
+    public PolicyTypeOperation(final PropertyOperation propertyOperation, final DerivedFromOperation derivedFromOperation,
+                               final OperationUtils operationUtils) {
+        this.propertyOperation = propertyOperation;
+        this.derivedFromOperation = derivedFromOperation;
+        this.operationUtils = operationUtils;
+    }
 
     @Override
     public Either<PolicyTypeDefinition, StorageOperationStatus> getLatestPolicyTypeByType(String type, String model) {
@@ -328,4 +335,18 @@ public class PolicyTypeOperation extends AbstractOperation implements IPolicyTyp
         updatedTypeDefinition.setCreationTime(currTypeDefinition.getCreationTime());
         updatedTypeDefinition.setModificationTime(System.currentTimeMillis());
     }
+
+    public void deletePolicyTypesByModelId(final String modelId) {
+        final JanusGraph janusGraph = janusGraphGenericDao.getJanusGraph();
+        final GraphTraversalSource traversal = janusGraph.traversal();
+        final List<Vertex> policyTypeList = traversal.V()
+            .has(GraphPropertiesDictionary.UNIQUE_ID.getProperty(), modelId)
+            .out(GraphEdgeLabels.MODEL_ELEMENT.getProperty())
+            .has(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.PolicyType.getName())
+            .toList();
+        policyTypeList.forEach(policyTypeVertex -> {
+            traversal.V(policyTypeVertex).out(GraphEdgeLabels.PROPERTY.getProperty()).drop().iterate();
+            policyTypeVertex.remove();
+        });
+    }
 }
index 01dbb07..bf8d6ae 100644 (file)
@@ -119,15 +119,19 @@ public class PropertyOperation extends AbstractOperation implements IPropertyOpe
     private static final String THE_VALUE_OF_PROPERTY_FROM_TYPE_IS_INVALID = "The value {} of property from type {} is invalid";
     private static final String PROPERTY = "Property";
     private static final String UPDATE_DATA_TYPE = "UpdateDataType";
-    private static Logger log = Logger.getLogger(PropertyOperation.class.getName());
-    private DerivedFromOperation derivedFromOperation;
+    private static final Logger log = Logger.getLogger(PropertyOperation.class.getName());
+    private final DerivedFromOperation derivedFromOperation;
     private DataTypeOperation dataTypeOperation;
 
     @Autowired
-    public PropertyOperation(HealingJanusGraphGenericDao janusGraphGenericDao, DerivedFromOperation derivedFromOperation,
-                             DataTypeOperation dataTypeOperation) {
+    public PropertyOperation(final HealingJanusGraphGenericDao janusGraphGenericDao, final DerivedFromOperation derivedFromOperation) {
         this.janusGraphGenericDao = janusGraphGenericDao;
         this.derivedFromOperation = derivedFromOperation;
+    }
+
+    //circular dependency DataTypeOperation->ModelOperation->ModelElementOperation->PropertyOperation
+    @Autowired
+    public void setDataTypeOperation(DataTypeOperation dataTypeOperation) {
         this.dataTypeOperation = dataTypeOperation;
     }
 
@@ -2264,4 +2268,5 @@ public class PropertyOperation extends AbstractOperation implements IPropertyOpe
             return null;
         }
     }
+
 }
index d93b798..1580fd3 100644 (file)
@@ -38,7 +38,6 @@ import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 import org.openecomp.sdc.be.model.DataTypeDefinition;
 import org.openecomp.sdc.be.model.Model;
-import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
 import org.openecomp.sdc.be.resources.data.DataTypeData;
 import org.springframework.test.context.ContextConfiguration;
 
@@ -51,8 +50,6 @@ class DataTypeOperationTest {
     private ModelOperation modelOperation;
     @Mock
     private HealingJanusGraphGenericDao janusGraphGenericDao;
-    @Mock
-    private ApplicationDataTypeCache applicationDataTypeCache;
 
     private final String modelName = "ETSI-SDC-MODEL-TEST";
     private final List<DataTypeData> dataTypesWithoutModel = new ArrayList<>();
@@ -61,10 +58,10 @@ class DataTypeOperationTest {
     final Map<String, DataTypeDefinition> allDataTypesFoundDefinitionMap = new HashMap<>();
     private Model model;
 
-
     @BeforeEach
     void beforeEachInit() {
         MockitoAnnotations.openMocks(this);
+        dataTypeOperation.setModelOperation(modelOperation);
         initTestData();
     }
 
diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelElementOperationTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelElementOperationTest.java
new file mode 100644 (file)
index 0000000..3de1369
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.model.operations.impl;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao;
+import org.openecomp.sdc.be.model.Model;
+
+class ModelElementOperationTest {
+
+    @Mock
+    private JanusGraphGenericDao janusGraphGenericDao;
+    @Mock
+    private DataTypeOperation dataTypeOperation;
+    @Mock
+    private PolicyTypeOperation policyTypeOperation;
+    @InjectMocks
+    private ModelElementOperation modelElementOperation;
+
+    @BeforeEach
+    void setUp() {
+        MockitoAnnotations.openMocks(this);
+    }
+
+    @Test
+    void deleteModelElements_noTransactionSuccessTest() {
+        var model = new Model("name");
+        final String modelId = UniqueIdBuilder.buildModelUid(model.getName());
+        modelElementOperation.deleteModelElements(model, false);
+        verify(dataTypeOperation).deleteDataTypesByModelId(modelId);
+        verify(policyTypeOperation).deletePolicyTypesByModelId(modelId);
+        verify(janusGraphGenericDao).commit();
+        verify(janusGraphGenericDao, times(0)).rollback();
+    }
+
+    @Test
+    void deleteModelElements_inTransactionSuccessTest() {
+        var model = new Model("name");
+        final String modelId = UniqueIdBuilder.buildModelUid(model.getName());
+        modelElementOperation.deleteModelElements(model, true);
+        verify(dataTypeOperation).deleteDataTypesByModelId(modelId);
+        verify(policyTypeOperation).deletePolicyTypesByModelId(modelId);
+        verify(janusGraphGenericDao, times(0)).commit();
+        verify(janusGraphGenericDao, times(0)).rollback();
+    }
+
+    @Test
+    void deleteModelElements_noTransactionErrorTest() {
+        var model = new Model("name");
+        final String modelId = UniqueIdBuilder.buildModelUid(model.getName());
+        doThrow(new RuntimeException()).when(dataTypeOperation).deleteDataTypesByModelId(modelId);
+        assertThrows(RuntimeException.class, () -> modelElementOperation.deleteModelElements(model, false));
+        verify(dataTypeOperation).deleteDataTypesByModelId(modelId);
+        verify(janusGraphGenericDao).rollback();
+        verify(janusGraphGenericDao, times(0)).commit();
+    }
+
+    @Test
+    void deleteModelElements_inTransactionErrorTest() {
+        var model = new Model("name");
+        final String modelId = UniqueIdBuilder.buildModelUid(model.getName());
+        doThrow(new RuntimeException()).when(dataTypeOperation).deleteDataTypesByModelId(modelId);
+        assertThrows(RuntimeException.class, () -> modelElementOperation.deleteModelElements(model, true));
+        verify(dataTypeOperation).deleteDataTypesByModelId(modelId);
+        verify(janusGraphGenericDao, times(0)).commit();
+        verify(janusGraphGenericDao, times(0)).rollback();
+    }
+}
\ No newline at end of file
index 793af71..a3c9bca 100644 (file)
@@ -73,12 +73,12 @@ public class PropertyOperationTest extends ModelTestBase {
 
     final DataTypeOperation dataTypeOperation = mock(DataTypeOperation.class);
 
-    PropertyOperation propertyOperation = new PropertyOperation(janusGraphGenericDao, null, dataTypeOperation);
+    PropertyOperation propertyOperation = new PropertyOperation(janusGraphGenericDao, null);
 
     @Before
     public void setup() {
+        propertyOperation.setDataTypeOperation(dataTypeOperation);
         propertyOperation.setJanusGraphGenericDao(janusGraphGenericDao);
-
     }
 
     private PropertyDefinition buildPropertyDefinition() {
@@ -456,9 +456,11 @@ public class PropertyOperationTest extends ModelTestBase {
 
        }
 
-       private PropertyOperation createTestSubject() {
-               return new PropertyOperation(new HealingJanusGraphGenericDao(new JanusGraphClient()), null, dataTypeOperation);
-       }
+    private PropertyOperation createTestSubject() {
+        final var propertyOperation = new PropertyOperation(new HealingJanusGraphGenericDao(new JanusGraphClient()), null);
+        propertyOperation.setDataTypeOperation(dataTypeOperation);
+        return propertyOperation;
+    }
 
        @Test
        public void testConvertPropertyDataToPropertyDefinition() throws Exception {
index a80e44e..b4f6156 100644 (file)
@@ -262,7 +262,7 @@ public class ToscaElementLifecycleOperationTest extends ModelTestBase {
         expectedIds.add(vertex4.getUniqueId());
         verifyInCatalogData(4, expectedIds);
 
-        lifecycleOperation.undoCheckout(vertex4.getUniqueId());
+        lifecycleOperation.undoCheckout(vertex4.getUniqueId(), null);
         expectedIds.remove(vertex4.getUniqueId());
         verifyInCatalogData(3, expectedIds);
 
index 69fb00f..0b1224a 100644 (file)
@@ -28,6 +28,10 @@ public abstract class BusinessException extends RuntimeException {
         super(message);
     }
 
+    protected BusinessException(final Throwable cause) {
+        super(cause);
+    }
+
     protected BusinessException(final String message, final Throwable cause) {
         super(message, cause);
     }