Support delete non-normative data types
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / operations / impl / ModelOperation.java
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021 Nordix Foundation
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19
20 package org.openecomp.sdc.be.model.operations.impl;
21
22 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DATA_TYPES;
23 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.PROPERTIES;
24 import static org.openecomp.sdc.common.api.Constants.ADDITIONAL_TYPE_DEFINITIONS;
25
26 import fj.data.Either;
27 import java.nio.charset.StandardCharsets;
28 import java.nio.file.Path;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.EnumMap;
32 import java.util.HashMap;
33 import java.util.LinkedHashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Map.Entry;
37 import java.util.Objects;
38 import java.util.Optional;
39 import java.util.Set;
40 import java.util.stream.Collectors;
41 import org.apache.commons.collections.CollectionUtils;
42 import org.apache.commons.collections.MapUtils;
43 import org.apache.commons.lang3.StringUtils;
44 import org.apache.commons.lang3.tuple.ImmutablePair;
45 import org.onap.sdc.tosca.services.YamlUtil;
46 import org.openecomp.sdc.be.dao.api.ActionStatus;
47 import org.openecomp.sdc.be.dao.cassandra.ToscaModelImportCassandraDao;
48 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
49 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
50 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphDao;
51 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao;
52 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
53 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
54 import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
55 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
56 import org.openecomp.sdc.be.data.model.ToscaImportByModel;
57 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
58 import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum;
59 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
60 import org.openecomp.sdc.be.model.Model;
61 import org.openecomp.sdc.be.model.dto.PropertyDefinitionDto;
62 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ModelOperationExceptionSupplier;
63 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
64 import org.openecomp.sdc.be.model.normatives.ElementTypeEnum;
65 import org.openecomp.sdc.be.model.operations.api.DerivedFromOperation;
66 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
67 import org.openecomp.sdc.be.resources.data.ModelData;
68 import org.openecomp.sdc.be.utils.TypeUtils;
69 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
70 import org.openecomp.sdc.common.log.wrappers.Logger;
71 import org.springframework.beans.factory.annotation.Autowired;
72 import org.springframework.stereotype.Component;
73 import org.yaml.snakeyaml.Yaml;
74
75 @Component("model-operation")
76 public class ModelOperation {
77
78     static final Path ADDITIONAL_TYPE_DEFINITIONS_PATH = Path.of(ADDITIONAL_TYPE_DEFINITIONS);
79     private static final Logger log = Logger.getLogger(ModelOperation.class);
80     private final JanusGraphGenericDao janusGraphGenericDao;
81     private final JanusGraphDao janusGraphDao;
82     private final ToscaModelImportCassandraDao toscaModelImportCassandraDao;
83     private final DerivedFromOperation derivedFromOperation;
84     private ModelElementOperation modelElementOperation;
85
86     @Autowired
87     public ModelOperation(final JanusGraphGenericDao janusGraphGenericDao,
88                           final JanusGraphDao janusGraphDao,
89                           final ToscaModelImportCassandraDao toscaModelImportCassandraDao,
90                           final DerivedFromOperation derivedFromOperation) {
91         this.janusGraphGenericDao = janusGraphGenericDao;
92         this.janusGraphDao = janusGraphDao;
93         this.toscaModelImportCassandraDao = toscaModelImportCassandraDao;
94         this.derivedFromOperation = derivedFromOperation;
95     }
96
97     public Model createModel(final Model model, final boolean inTransaction) {
98         Model result = null;
99         final var modelData = new ModelData(model.getName(), UniqueIdBuilder.buildModelUid(model.getName()), model.getModelType());
100         try {
101             final Either<ModelData, JanusGraphOperationStatus> createNode = janusGraphGenericDao.createNode(modelData, ModelData.class);
102             if (createNode.isRight()) {
103                 final var janusGraphOperationStatus = createNode.right().value();
104                 log.error(EcompLoggerErrorCode.DATA_ERROR, ModelOperation.class.getName(), "Problem while creating model, reason {}",
105                     janusGraphOperationStatus);
106                 if (janusGraphOperationStatus == JanusGraphOperationStatus.JANUSGRAPH_SCHEMA_VIOLATION) {
107                     throw ModelOperationExceptionSupplier.modelAlreadyExists(model.getName()).get();
108                 }
109                 throw new OperationException(ActionStatus.GENERAL_ERROR,
110                     String.format("Failed to create model %s on JanusGraph with %s error", model, janusGraphOperationStatus));
111             }
112             addDerivedFromRelation(model);
113             result = new Model(createNode.left().value().getName(), model.getDerivedFrom(), model.getModelType());
114             return result;
115         } finally {
116             if (!inTransaction) {
117                 if (Objects.nonNull(result)) {
118                     janusGraphGenericDao.commit();
119                 } else {
120                     janusGraphGenericDao.rollback();
121                 }
122             }
123         }
124     }
125
126     private void addDerivedFromRelation(final Model model) {
127         final String derivedFrom = model.getDerivedFrom();
128         if (derivedFrom == null) {
129             return;
130         }
131         log.debug("Adding derived from relation between model {} to its parent {}",
132             model.getName(), derivedFrom);
133         final Optional<Model> derivedFromModelOptional = this.findModelByName(derivedFrom);
134         if (derivedFromModelOptional.isPresent()) {
135             final Either<GraphRelation, StorageOperationStatus> result = derivedFromOperation.addDerivedFromRelation(
136                 UniqueIdBuilder.buildModelUid(model.getName()),
137                 UniqueIdBuilder.buildModelUid(derivedFromModelOptional.get().getName()), NodeTypeEnum.Model);
138             if (result.isRight()) {
139                 throw new OperationException(ActionStatus.GENERAL_ERROR,
140                     String.format("Failed to create relationship from model %s to derived from model %s on JanusGraph with %s error", model,
141                         derivedFrom, result.right().value()));
142             }
143         }
144     }
145
146     public Optional<GraphVertex> findModelVertexByName(final String name) {
147         if (StringUtils.isEmpty(name)) {
148             return Optional.empty();
149         }
150         final Map<GraphPropertyEnum, Object> props = new EnumMap<>(GraphPropertyEnum.class);
151         props.put(GraphPropertyEnum.NAME, name);
152         props.put(GraphPropertyEnum.UNIQUE_ID, UniqueIdBuilder.buildModelUid(name));
153         final List<GraphVertex> modelVerticesList = findModelVerticesByCriteria(props);
154         if (modelVerticesList.isEmpty()) {
155             return Optional.empty();
156         }
157         return Optional.ofNullable(modelVerticesList.get(0));
158     }
159
160     public Optional<Model> findModelByName(final String name) {
161         if (StringUtils.isEmpty(name)) {
162             return Optional.empty();
163         }
164         final Optional<GraphVertex> modelVertexOpt = findModelVertexByName(name);
165         if (modelVertexOpt.isEmpty()) {
166             return Optional.empty();
167         }
168
169         final GraphVertex graphVertex = modelVertexOpt.get();
170         return Optional.of(convertToModel(graphVertex));
171     }
172
173     public void createModelImports(final String modelId, final Map<String, byte[]> zipContent) {
174         if (MapUtils.isEmpty(zipContent)) {
175             return;
176         }
177         final List<ToscaImportByModel> toscaImportByModelList = zipContent.entrySet().stream()
178             .map(entry -> {
179                 final String path = entry.getKey();
180                 final byte[] bytes = entry.getValue();
181                 final String content = new String(bytes, StandardCharsets.UTF_8);
182                 final var toscaImportByModel = new ToscaImportByModel();
183                 toscaImportByModel.setModelId(modelId);
184                 toscaImportByModel.setFullPath(path);
185                 toscaImportByModel.setContent(content);
186                 return toscaImportByModel;
187             }).collect(Collectors.toList());
188         toscaModelImportCassandraDao.replaceImports(modelId, toscaImportByModelList);
189     }
190
191     /**
192      * Find all the model default imports, with the option to include the default imports from the parent model.
193      *
194      * @param modelId       the model id
195      * @param includeParent a flag to include the parent model imports.
196      * @return the list of model default imports, or an empty list if no imports were found.
197      */
198     public List<ToscaImportByModel> findAllModelImports(final String modelId, final boolean includeParent) {
199         final List<ToscaImportByModel> toscaImportByModelList = toscaModelImportCassandraDao.findAllByModel(modelId);
200         if (includeParent) {
201             findModelByName(modelId).ifPresent(model -> {
202                 if (model.getDerivedFrom() != null) {
203                     toscaImportByModelList.addAll(toscaModelImportCassandraDao.findAllByModel(model.getDerivedFrom()));
204                 }
205             });
206         }
207         toscaImportByModelList.sort((o1, o2) -> {
208             final int modelIdComparison = o1.getModelId().compareTo(o2.getModelId());
209             if (modelIdComparison == 0) {
210                 return o1.getFullPath().compareTo(o2.getFullPath());
211             }
212             return modelIdComparison;
213         });
214         return toscaImportByModelList;
215     }
216
217     /**
218      * Finds all the models.
219      *
220      * @return the list of models
221      */
222     public List<Model> findAllModels() {
223         return findModelsByCriteria(Collections.emptyMap());
224     }
225
226     public List<Model> findModels(final ModelTypeEnum modelType) {
227         final Map<GraphPropertyEnum, Object> propertyCriteria = new EnumMap<>(GraphPropertyEnum.class);
228         propertyCriteria.put(GraphPropertyEnum.MODEL_TYPE, modelType.getValue());
229
230         return findModelsByCriteria(propertyCriteria);
231     }
232
233     private List<Model> findModelsByCriteria(final Map<GraphPropertyEnum, Object> propertyCriteria) {
234         final List<GraphVertex> modelVerticesByCriteria = findModelVerticesByCriteria(propertyCriteria);
235         if (modelVerticesByCriteria.isEmpty()) {
236             return Collections.emptyList();
237         }
238
239         return modelVerticesByCriteria.stream().map(this::convertToModel).collect(Collectors.toList());
240     }
241
242     private List<GraphVertex> findModelVerticesByCriteria(final Map<GraphPropertyEnum, Object> propertyCriteria) {
243         final Either<List<GraphVertex>, JanusGraphOperationStatus> result = janusGraphDao.getByCriteria(VertexTypeEnum.MODEL, propertyCriteria);
244         if (result.isRight()) {
245             final var janusGraphOperationStatus = result.right().value();
246             if (janusGraphOperationStatus == JanusGraphOperationStatus.NOT_FOUND) {
247                 return Collections.emptyList();
248             }
249             final var operationException = ModelOperationExceptionSupplier.failedToRetrieveModels(janusGraphOperationStatus).get();
250             log.error(EcompLoggerErrorCode.DATA_ERROR, this.getClass().getName(), operationException.getMessage());
251             throw operationException;
252         }
253         return result.left().value();
254     }
255
256     private Model convertToModel(final GraphVertex modelGraphVertex) {
257         final String modelName = (String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.NAME);
258         final String modelTypeProperty = (String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.MODEL_TYPE);
259         ModelTypeEnum modelType = ModelTypeEnum.NORMATIVE;
260         final Optional<ModelTypeEnum> optionalModelTypeEnum = ModelTypeEnum.findByValue(modelTypeProperty);
261         if (optionalModelTypeEnum.isPresent()) {
262             modelType = optionalModelTypeEnum.get();
263         }
264
265         final Either<ImmutablePair<ModelData, GraphEdge>, JanusGraphOperationStatus> parentNode =
266             janusGraphGenericDao.getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Model), UniqueIdBuilder.buildModelUid(modelName),
267                 GraphEdgeLabels.DERIVED_FROM, NodeTypeEnum.Model, ModelData.class);
268         log.debug("After retrieving DERIVED_FROM node of {}. status is {}", modelName, parentNode);
269         if (parentNode.isRight()) {
270             final JanusGraphOperationStatus janusGraphOperationStatus = parentNode.right().value();
271             if (janusGraphOperationStatus != JanusGraphOperationStatus.NOT_FOUND) {
272                 final var operationException = ModelOperationExceptionSupplier.failedToRetrieveModels(janusGraphOperationStatus).get();
273                 log.error(EcompLoggerErrorCode.DATA_ERROR, this.getClass().getName(), operationException.getMessage());
274                 throw operationException;
275             }
276             return new Model((String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.NAME), modelType);
277         } else {
278             final ModelData parentModel = parentNode.left().value().getKey();
279             return new Model((String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.NAME), parentModel.getName(), modelType);
280         }
281     }
282
283     public void addTypesToDefaultImports(final ElementTypeEnum elementTypeEnum, final String typesYaml, final String modelName) {
284         final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName);
285         final Optional<ToscaImportByModel> additionalTypeDefinitionsImportOptional = modelImportList.stream()
286             .filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny();
287         final ToscaImportByModel additionalTypeDefinitionsImport;
288         final List<ToscaImportByModel> rebuiltModelImportList;
289         if (additionalTypeDefinitionsImportOptional.isPresent()) {
290             additionalTypeDefinitionsImport = additionalTypeDefinitionsImportOptional.get();
291             rebuiltModelImportList = modelImportList.stream()
292                 .filter(toscaImportByModel -> !ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(toscaImportByModel.getFullPath())))
293                 .collect(Collectors.toList());
294         } else {
295             additionalTypeDefinitionsImport = new ToscaImportByModel();
296             additionalTypeDefinitionsImport.setModelId(modelName);
297             additionalTypeDefinitionsImport.setFullPath(ADDITIONAL_TYPE_DEFINITIONS_PATH.toString());
298             additionalTypeDefinitionsImport.setContent(createAdditionalTypeDefinitionsHeader());
299             rebuiltModelImportList = new ArrayList<>(modelImportList);
300         }
301
302         Map<String, Object> typesYamlMap = new Yaml().loadAs(typesYaml, Map.class);
303         if (typesYamlMap.containsKey(DATA_TYPES.getElementName())) {
304             typesYamlMap = (Map<String, Object>) typesYamlMap.get(DATA_TYPES.getElementName());
305         }
306         removeExistingTypesFromDefaultImports(elementTypeEnum, typesYamlMap, rebuiltModelImportList);
307
308         final Map<String, Object> originalContent = new Yaml().load(additionalTypeDefinitionsImport.getContent());
309         additionalTypeDefinitionsImport.setContent(buildAdditionalTypeDefinitionsContent(elementTypeEnum, typesYamlMap, originalContent));
310         rebuiltModelImportList.add(additionalTypeDefinitionsImport);
311
312         toscaModelImportCassandraDao.saveAll(modelName, rebuiltModelImportList);
313     }
314
315     private void removeExistingTypesFromDefaultImports(final ElementTypeEnum elementTypeEnum, final Map<String, Object> typesYaml,
316                                                        final List<ToscaImportByModel> defaultImportList) {
317         defaultImportList.forEach(toscaImportByModel -> {
318             final Map<String, Object> existingImportYamlMap = new Yaml().load(toscaImportByModel.getContent());
319             final Map<String, Object> currentTypeYamlMap = (Map<String, Object>) existingImportYamlMap.get(elementTypeEnum.getToscaEntryName());
320             if (MapUtils.isNotEmpty(currentTypeYamlMap)) {
321                 typesYaml.keySet().forEach(currentTypeYamlMap::remove);
322             }
323             toscaImportByModel.setContent(new YamlUtil().objectToYaml(existingImportYamlMap));
324         });
325     }
326
327     private String buildAdditionalTypeDefinitionsContent(final ElementTypeEnum elementTypeEnum, final Map<String, Object> typesYamlMap,
328                                                          final Map<String, Object> originalContent) {
329         final Map<String, Object> originalTypeContent = (Map<String, Object>) originalContent.get(elementTypeEnum.getToscaEntryName());
330         if (MapUtils.isEmpty(originalTypeContent)) {
331             originalContent.put(elementTypeEnum.getToscaEntryName(), new LinkedHashMap<>(typesYamlMap));
332         } else {
333             originalTypeContent.putAll(typesYamlMap);
334         }
335         return new YamlUtil().objectToYaml(originalContent);
336     }
337
338     private String createAdditionalTypeDefinitionsHeader() {
339         return "tosca_definitions_version: tosca_simple_yaml_1_3" + "\n"
340             + "description: Auto-generated file that contains package custom types or types added after system installation." + "\n";
341     }
342
343     /**
344      * Deletes the given model if it exists, along with its MODEL_ELEMENT edges and import files.
345      *
346      * @param model         the model
347      * @param inTransaction if the operation is called in the middle of a janusgraph transaction
348      */
349     public void deleteModel(final Model model, final boolean inTransaction) {
350         boolean rollback = false;
351
352         try {
353             final GraphVertex modelVertexByName = findModelVertexByName(model.getName()).orElse(null);
354             if (modelVertexByName == null) {
355                 return;
356             }
357             toscaModelImportCassandraDao.deleteAllByModel(model.getName());
358             modelElementOperation.deleteModelElements(model, inTransaction);
359             deleteModel(model);
360         } catch (final OperationException e) {
361             rollback = true;
362             throw e;
363         } catch (final Exception e) {
364             rollback = true;
365             throw new OperationException(e, ActionStatus.COULD_NOT_DELETE_MODEL, model.getName());
366         } finally {
367             if (!inTransaction) {
368                 if (rollback) {
369                     janusGraphGenericDao.rollback();
370                 } else {
371                     janusGraphGenericDao.commit();
372                 }
373             }
374         }
375     }
376
377     private void deleteModel(final Model model) {
378         final var modelData = new ModelData(model.getName(), UniqueIdBuilder.buildModelUid(model.getName()), model.getModelType());
379         final Either<ModelData, JanusGraphOperationStatus> deleteParentNodeByModel = janusGraphGenericDao.deleteNode(modelData, ModelData.class);
380         if (deleteParentNodeByModel.isRight()) {
381             final var janusGraphOperationStatus = deleteParentNodeByModel.right().value();
382             log.error(EcompLoggerErrorCode.DATA_ERROR, ModelOperation.class.getName(),
383                 "Failed to delete model {} on JanusGraph with status {}", model.getName(), janusGraphOperationStatus);
384             throw new OperationException(ActionStatus.COULD_NOT_DELETE_MODEL, model.getName());
385         }
386     }
387
388     @Autowired
389     public void setModelElementOperation(final ModelElementOperation modelElementOperation) {
390         this.modelElementOperation = modelElementOperation;
391     }
392
393     @SuppressWarnings("unchecked")
394     public void updateTypesInAdditionalTypesImport(final ElementTypeEnum elementTypeEnum, final String typesYaml, final String modelName) {
395         final Optional<ToscaImportByModel> additionalTypeDefinitionsImportOptional = getAdditionalTypes(modelName);
396
397         if (additionalTypeDefinitionsImportOptional.isPresent()) {
398
399             final Map<String, Object> existingTypeContent = getExistingTypes(elementTypeEnum, additionalTypeDefinitionsImportOptional.get());
400             final Set<String> existingTypeNames = existingTypeContent.keySet();
401
402             Map<String, Object> newTypesYaml = new Yaml().load(typesYaml);
403             if (newTypesYaml.containsKey(DATA_TYPES.getElementName())) {
404                 newTypesYaml = (Map<String, Object>) newTypesYaml.get(DATA_TYPES.getElementName());
405             }
406             final Map<String, Object> typesToUpate = new HashMap<>();
407             newTypesYaml.entrySet().stream().filter(entry -> existingTypeNames.contains(entry.getKey())).forEach(newTypeToUpdate -> {
408
409                 final Map<String, Object> propertiesInNewDef =
410                     (Map<String, Object>) ((Map<String, Object>) newTypeToUpdate.getValue()).get(PROPERTIES.getElementName());
411                 final Map<String, Object> existingProperties =
412                     (Map<String, Object>) ((Map<String, Object>) existingTypeContent.get(newTypeToUpdate.getKey())).get(PROPERTIES.getElementName());
413
414                 final List<Entry<String, Object>> propertiesMissingFromNewDef = MapUtils.isEmpty(existingProperties) ? Collections.emptyList() :
415                     existingProperties.entrySet().stream()
416                         .filter(existingPropEntry -> !propertiesInNewDef.keySet().contains(existingPropEntry.getKey())).collect(Collectors.toList());
417
418                 if (CollectionUtils.isNotEmpty(propertiesMissingFromNewDef)) {
419                     typesToUpate.put(newTypeToUpdate.getKey(), newTypeToUpdate.getValue());
420
421                     propertiesMissingFromNewDef
422                         .forEach(existingPropToAdd -> propertiesInNewDef.put(existingPropToAdd.getKey(), existingPropToAdd.getValue()));
423                 }
424             });
425             if (MapUtils.isNotEmpty(typesToUpate)) {
426                 addTypesToDefaultImports(elementTypeEnum, new Yaml().dumpAsMap(typesToUpate), modelName);
427             }
428         }
429     }
430
431     private Optional<ToscaImportByModel> getAdditionalTypes(final String modelName) {
432         final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName);
433         return modelImportList.stream().filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny();
434     }
435
436     private Map<String, Object> getExistingTypes(final ElementTypeEnum elementTypeEnum, final ToscaImportByModel additionalTypeDefinitionsImport) {
437         final Map<String, Object> existingContent = new Yaml().load(additionalTypeDefinitionsImport.getContent());
438         return (Map<String, Object>) existingContent.get(elementTypeEnum.getToscaEntryName());
439     }
440
441     public void updatePropertyInAdditionalType(final ElementTypeEnum elementTypeEnum, final PropertyDefinitionDto property,
442                                                final String modelName, final String name, boolean isAdd) {
443         final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName);
444         final Optional<ToscaImportByModel> additionalTypeDefinitionsImportOptional = modelImportList.stream()
445             .filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny();
446         if (additionalTypeDefinitionsImportOptional.isEmpty()) {
447             return;
448         }
449         final ToscaImportByModel additionalTypeDefinitionsImport = additionalTypeDefinitionsImportOptional.get();
450         final List<ToscaImportByModel> rebuiltModelImportList = modelImportList.stream()
451             .filter(toscaImportByModel -> !ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(toscaImportByModel.getFullPath())))
452             .collect(Collectors.toList());
453         final Map<String, Object> originalContent = new Yaml().load(additionalTypeDefinitionsImport.getContent());
454         additionalTypeDefinitionsImport.setContent(
455             buildPropertyAdditionalTypeDefinitionContent(elementTypeEnum, name, property, originalContent, isAdd));
456         rebuiltModelImportList.add(additionalTypeDefinitionsImport);
457         toscaModelImportCassandraDao.saveAll(modelName, rebuiltModelImportList);
458     }
459
460     public void removeDataTypeFromAdditionalType(final ElementTypeEnum elementTypeEnum, final String modelName, final String name) {
461         final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName);
462         final Optional<ToscaImportByModel> additionalTypeDefinitionsImportOptional = modelImportList.stream()
463             .filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny();
464         if (additionalTypeDefinitionsImportOptional.isEmpty()) {
465             return;
466         }
467         final ToscaImportByModel additionalTypeDefinitionsImport = additionalTypeDefinitionsImportOptional.get();
468         removeExistingTypesFromDefaultImports(elementTypeEnum, Collections.singletonMap(name, null),
469             Collections.singletonList(additionalTypeDefinitionsImport));
470         final List<ToscaImportByModel> rebuiltModelImportList = modelImportList.stream()
471             .filter(toscaImportByModel -> !ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(toscaImportByModel.getFullPath())))
472             .collect(Collectors.toList());
473         rebuiltModelImportList.add(additionalTypeDefinitionsImport);
474         toscaModelImportCassandraDao.saveAll(modelName, rebuiltModelImportList);
475     }
476
477     private String buildPropertyAdditionalTypeDefinitionContent(final ElementTypeEnum elementTypeEnum, final String name,
478                                                                 final PropertyDefinitionDto property, final Map<String, Object> originalContent,
479                                                                 boolean isAdd) {
480         final Map<String, Object> originalTypeContent = (Map<String, Object>) originalContent.get(elementTypeEnum.getToscaEntryName());
481         Map<String, Object> typeContent = (Map<String, Object>) originalTypeContent.get(name);
482         Map<String, Object> typeProperties = (Map<String, Object>) typeContent.get(PROPERTIES.getElementName());
483         if (MapUtils.isEmpty(typeProperties)) {
484             typeProperties = new HashMap<>();
485         }
486         if (isAdd) {
487             typeProperties.put(property.getName(), constructProperty(property));
488         } else {
489             typeProperties.remove(property.getName());
490         }
491         typeContent.put(PROPERTIES.getElementName(), typeProperties);
492         return new YamlUtil().objectToYaml(originalContent);
493     }
494
495     private Map<String, Object> constructProperty(final PropertyDefinitionDto property) {
496         Map<String, Object> typeProp = new HashMap<>();
497         if (property.getType() != null) {
498             typeProp.put(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName(), property.getType());
499         }
500         if (property.getDescription() != null) {
501             typeProp.put(TypeUtils.ToscaTagNamesEnum.DESCRIPTION.getElementName(), property.getDescription());
502         }
503         Map<String, Object> schema = new HashMap<>();
504         if (property.getSchemaType() != null) {
505             schema.put(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName(), property.getSchemaType());
506             typeProp.put(TypeUtils.ToscaTagNamesEnum.ENTRY_SCHEMA.getElementName(), schema);
507         }
508         if (property.getDefaultValue() != null) {
509             typeProp.put(TypeUtils.ToscaTagNamesEnum.DEFAULT.getElementName(), property.getDefaultValue());
510         }
511         if (property.getRequired() != null) {
512             typeProp.put(TypeUtils.ToscaTagNamesEnum.REQUIRED.getElementName(), property.getRequired());
513         }
514         if (property.getConstraints() != null) {
515             typeProp.put(TypeUtils.ToscaTagNamesEnum.CONSTRAINTS.getElementName(), property.getConstraints());
516         }
517         return typeProp;
518     }
519
520 }