Release version 1.13.7
[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.PropertyConstraint;
62 import org.openecomp.sdc.be.model.dto.PropertyDefinitionDto;
63 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ModelOperationExceptionSupplier;
64 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
65 import org.openecomp.sdc.be.model.normatives.ElementTypeEnum;
66 import org.openecomp.sdc.be.model.operations.api.DerivedFromOperation;
67 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
68 import org.openecomp.sdc.be.model.tosca.constraints.EqualConstraint;
69 import org.openecomp.sdc.be.model.tosca.constraints.GreaterOrEqualConstraint;
70 import org.openecomp.sdc.be.model.tosca.constraints.GreaterThanConstraint;
71 import org.openecomp.sdc.be.model.tosca.constraints.InRangeConstraint;
72 import org.openecomp.sdc.be.model.tosca.constraints.LengthConstraint;
73 import org.openecomp.sdc.be.model.tosca.constraints.LessOrEqualConstraint;
74 import org.openecomp.sdc.be.model.tosca.constraints.LessThanConstraint;
75 import org.openecomp.sdc.be.model.tosca.constraints.MaxLengthConstraint;
76 import org.openecomp.sdc.be.model.tosca.constraints.MinLengthConstraint;
77 import org.openecomp.sdc.be.model.tosca.constraints.PatternConstraint;
78 import org.openecomp.sdc.be.model.tosca.constraints.ValidValuesConstraint;
79 import org.openecomp.sdc.be.resources.data.ModelData;
80 import org.openecomp.sdc.be.utils.TypeUtils;
81 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
82 import org.openecomp.sdc.common.log.wrappers.Logger;
83 import org.springframework.beans.factory.annotation.Autowired;
84 import org.springframework.stereotype.Component;
85 import org.yaml.snakeyaml.Yaml;
86
87 @Component("model-operation")
88 public class ModelOperation {
89
90     public static final Path ADDITIONAL_TYPE_DEFINITIONS_PATH = Path.of(ADDITIONAL_TYPE_DEFINITIONS);
91     private static final Logger log = Logger.getLogger(ModelOperation.class);
92     private final JanusGraphGenericDao janusGraphGenericDao;
93     private final JanusGraphDao janusGraphDao;
94     private final ToscaModelImportCassandraDao toscaModelImportCassandraDao;
95     private final DerivedFromOperation derivedFromOperation;
96     private ModelElementOperation modelElementOperation;
97
98     @Autowired
99     public ModelOperation(final JanusGraphGenericDao janusGraphGenericDao,
100                           final JanusGraphDao janusGraphDao,
101                           final ToscaModelImportCassandraDao toscaModelImportCassandraDao,
102                           final DerivedFromOperation derivedFromOperation) {
103         this.janusGraphGenericDao = janusGraphGenericDao;
104         this.janusGraphDao = janusGraphDao;
105         this.toscaModelImportCassandraDao = toscaModelImportCassandraDao;
106         this.derivedFromOperation = derivedFromOperation;
107     }
108
109     public Model createModel(final Model model, final boolean inTransaction) {
110         Model result = null;
111         final var modelData = new ModelData(model.getName(), UniqueIdBuilder.buildModelUid(model.getName()), model.getModelType());
112         try {
113             final Either<ModelData, JanusGraphOperationStatus> createNode = janusGraphGenericDao.createNode(modelData, ModelData.class);
114             if (createNode.isRight()) {
115                 final var janusGraphOperationStatus = createNode.right().value();
116                 log.error(EcompLoggerErrorCode.DATA_ERROR, ModelOperation.class.getName(), "Problem while creating model, reason {}",
117                     janusGraphOperationStatus);
118                 if (janusGraphOperationStatus == JanusGraphOperationStatus.JANUSGRAPH_SCHEMA_VIOLATION) {
119                     throw ModelOperationExceptionSupplier.modelAlreadyExists(model.getName()).get();
120                 }
121                 throw new OperationException(ActionStatus.GENERAL_ERROR,
122                     String.format("Failed to create model %s on JanusGraph with %s error", model, janusGraphOperationStatus));
123             }
124             addDerivedFromRelation(model);
125             result = new Model(createNode.left().value().getName(), model.getDerivedFrom(), model.getModelType());
126             return result;
127         } finally {
128             if (!inTransaction) {
129                 if (Objects.nonNull(result)) {
130                     janusGraphGenericDao.commit();
131                 } else {
132                     janusGraphGenericDao.rollback();
133                 }
134             }
135         }
136     }
137
138     private void addDerivedFromRelation(final Model model) {
139         final String derivedFrom = model.getDerivedFrom();
140         if (derivedFrom == null) {
141             return;
142         }
143         log.debug("Adding derived from relation between model {} to its parent {}",
144             model.getName(), derivedFrom);
145         final Optional<Model> derivedFromModelOptional = this.findModelByName(derivedFrom);
146         if (derivedFromModelOptional.isPresent()) {
147             final Either<GraphRelation, StorageOperationStatus> result = derivedFromOperation.addDerivedFromRelation(
148                 UniqueIdBuilder.buildModelUid(model.getName()),
149                 UniqueIdBuilder.buildModelUid(derivedFromModelOptional.get().getName()), NodeTypeEnum.Model);
150             if (result.isRight()) {
151                 throw new OperationException(ActionStatus.GENERAL_ERROR,
152                     String.format("Failed to create relationship from model %s to derived from model %s on JanusGraph with %s error", model,
153                         derivedFrom, result.right().value()));
154             }
155         }
156     }
157
158     public Optional<GraphVertex> findModelVertexByName(final String name) {
159         if (StringUtils.isEmpty(name)) {
160             return Optional.empty();
161         }
162         final Map<GraphPropertyEnum, Object> props = new EnumMap<>(GraphPropertyEnum.class);
163         props.put(GraphPropertyEnum.NAME, name);
164         props.put(GraphPropertyEnum.UNIQUE_ID, UniqueIdBuilder.buildModelUid(name));
165         final List<GraphVertex> modelVerticesList = findModelVerticesByCriteria(props);
166         if (modelVerticesList.isEmpty()) {
167             return Optional.empty();
168         }
169         return Optional.ofNullable(modelVerticesList.get(0));
170     }
171
172     public Optional<Model> findModelByName(final String name) {
173         if (StringUtils.isEmpty(name)) {
174             return Optional.empty();
175         }
176         final Optional<GraphVertex> modelVertexOpt = findModelVertexByName(name);
177         if (modelVertexOpt.isEmpty()) {
178             return Optional.empty();
179         }
180
181         final GraphVertex graphVertex = modelVertexOpt.get();
182         return Optional.of(convertToModel(graphVertex));
183     }
184
185     public void createModelImports(final String modelId, final Map<String, byte[]> zipContent) {
186         if (MapUtils.isEmpty(zipContent)) {
187             return;
188         }
189         final List<ToscaImportByModel> toscaImportByModelList = zipContent.entrySet().stream()
190             .map(entry -> {
191                 final String path = entry.getKey();
192                 final byte[] bytes = entry.getValue();
193                 final String content = new String(bytes, StandardCharsets.UTF_8);
194                 final var toscaImportByModel = new ToscaImportByModel();
195                 toscaImportByModel.setModelId(modelId);
196                 toscaImportByModel.setFullPath(path);
197                 toscaImportByModel.setContent(content);
198                 return toscaImportByModel;
199             }).collect(Collectors.toList());
200         toscaModelImportCassandraDao.replaceImports(modelId, toscaImportByModelList);
201     }
202
203     /**
204      * Find all the model default imports, with the option to include the default imports from the parent model.
205      *
206      * @param modelId       the model id
207      * @param includeParent a flag to include the parent model imports.
208      * @return the list of model default imports, or an empty list if no imports were found.
209      */
210     public List<ToscaImportByModel> findAllModelImports(final String modelId, final boolean includeParent) {
211         final List<ToscaImportByModel> toscaImportByModelList = toscaModelImportCassandraDao.findAllByModel(modelId);
212         if (includeParent) {
213             findModelByName(modelId).ifPresent(model -> {
214                 if (model.getDerivedFrom() != null) {
215                     toscaImportByModelList.addAll(toscaModelImportCassandraDao.findAllByModel(model.getDerivedFrom()));
216                 }
217             });
218         }
219         toscaImportByModelList.sort((o1, o2) -> {
220             final int modelIdComparison = o1.getModelId().compareTo(o2.getModelId());
221             if (modelIdComparison == 0) {
222                 return o1.getFullPath().compareTo(o2.getFullPath());
223             }
224             return modelIdComparison;
225         });
226         return toscaImportByModelList;
227     }
228
229     /**
230      * Finds all the models.
231      *
232      * @return the list of models
233      */
234     public List<Model> findAllModels() {
235         return findModelsByCriteria(Collections.emptyMap());
236     }
237
238     public List<Model> findModels(final ModelTypeEnum modelType) {
239         final Map<GraphPropertyEnum, Object> propertyCriteria = new EnumMap<>(GraphPropertyEnum.class);
240         propertyCriteria.put(GraphPropertyEnum.MODEL_TYPE, modelType.getValue());
241
242         return findModelsByCriteria(propertyCriteria);
243     }
244
245     private List<Model> findModelsByCriteria(final Map<GraphPropertyEnum, Object> propertyCriteria) {
246         final List<GraphVertex> modelVerticesByCriteria = findModelVerticesByCriteria(propertyCriteria);
247         if (modelVerticesByCriteria.isEmpty()) {
248             return Collections.emptyList();
249         }
250
251         return modelVerticesByCriteria.stream().map(this::convertToModel).collect(Collectors.toList());
252     }
253
254     private List<GraphVertex> findModelVerticesByCriteria(final Map<GraphPropertyEnum, Object> propertyCriteria) {
255         final Either<List<GraphVertex>, JanusGraphOperationStatus> result = janusGraphDao.getByCriteria(VertexTypeEnum.MODEL, propertyCriteria);
256         if (result.isRight()) {
257             final var janusGraphOperationStatus = result.right().value();
258             if (janusGraphOperationStatus == JanusGraphOperationStatus.NOT_FOUND) {
259                 return Collections.emptyList();
260             }
261             final var operationException = ModelOperationExceptionSupplier.failedToRetrieveModels(janusGraphOperationStatus).get();
262             log.error(EcompLoggerErrorCode.DATA_ERROR, this.getClass().getName(), operationException.getMessage());
263             throw operationException;
264         }
265         return result.left().value();
266     }
267
268     private Model convertToModel(final GraphVertex modelGraphVertex) {
269         final String modelName = (String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.NAME);
270         final String modelTypeProperty = (String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.MODEL_TYPE);
271         ModelTypeEnum modelType = ModelTypeEnum.NORMATIVE;
272         final Optional<ModelTypeEnum> optionalModelTypeEnum = ModelTypeEnum.findByValue(modelTypeProperty);
273         if (optionalModelTypeEnum.isPresent()) {
274             modelType = optionalModelTypeEnum.get();
275         }
276
277         final Either<ImmutablePair<ModelData, GraphEdge>, JanusGraphOperationStatus> parentNode =
278             janusGraphGenericDao.getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Model), UniqueIdBuilder.buildModelUid(modelName),
279                 GraphEdgeLabels.DERIVED_FROM, NodeTypeEnum.Model, ModelData.class);
280         log.debug("After retrieving DERIVED_FROM node of {}. status is {}", modelName, parentNode);
281         if (parentNode.isRight()) {
282             final JanusGraphOperationStatus janusGraphOperationStatus = parentNode.right().value();
283             if (janusGraphOperationStatus != JanusGraphOperationStatus.NOT_FOUND) {
284                 final var operationException = ModelOperationExceptionSupplier.failedToRetrieveModels(janusGraphOperationStatus).get();
285                 log.error(EcompLoggerErrorCode.DATA_ERROR, this.getClass().getName(), operationException.getMessage());
286                 throw operationException;
287             }
288             return new Model((String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.NAME), modelType);
289         } else {
290             final ModelData parentModel = parentNode.left().value().getKey();
291             return new Model((String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.NAME), parentModel.getName(), modelType);
292         }
293     }
294
295     public void addTypesToDefaultImports(final ElementTypeEnum elementTypeEnum, final String typesYaml, final String modelName) {
296         final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName);
297         final Optional<ToscaImportByModel> additionalTypeDefinitionsImportOptional = modelImportList.stream()
298             .filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny();
299         final ToscaImportByModel additionalTypeDefinitionsImport;
300         final List<ToscaImportByModel> rebuiltModelImportList;
301         if (additionalTypeDefinitionsImportOptional.isPresent()) {
302             additionalTypeDefinitionsImport = additionalTypeDefinitionsImportOptional.get();
303             rebuiltModelImportList = modelImportList.stream()
304                 .filter(toscaImportByModel -> !ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(toscaImportByModel.getFullPath())))
305                 .collect(Collectors.toList());
306         } else {
307             additionalTypeDefinitionsImport = new ToscaImportByModel();
308             additionalTypeDefinitionsImport.setModelId(modelName);
309             additionalTypeDefinitionsImport.setFullPath(ADDITIONAL_TYPE_DEFINITIONS_PATH.toString());
310             additionalTypeDefinitionsImport.setContent(createAdditionalTypeDefinitionsHeader());
311             rebuiltModelImportList = new ArrayList<>(modelImportList);
312         }
313
314         Map<String, Object> typesYamlMap = new Yaml().loadAs(typesYaml, Map.class);
315         if (typesYamlMap.containsKey(DATA_TYPES.getElementName())) {
316             typesYamlMap = (Map<String, Object>) typesYamlMap.get(DATA_TYPES.getElementName());
317         }
318         removeExistingTypesFromDefaultImports(elementTypeEnum, typesYamlMap, rebuiltModelImportList);
319
320         final Map<String, Object> originalContent = new Yaml().load(additionalTypeDefinitionsImport.getContent());
321         additionalTypeDefinitionsImport.setContent(buildAdditionalTypeDefinitionsContent(elementTypeEnum, typesYamlMap, originalContent));
322         rebuiltModelImportList.add(additionalTypeDefinitionsImport);
323
324         toscaModelImportCassandraDao.saveAll(modelName, rebuiltModelImportList);
325     }
326
327     private void removeExistingTypesFromDefaultImports(final ElementTypeEnum elementTypeEnum, final Map<String, Object> typesYaml,
328                                                        final List<ToscaImportByModel> defaultImportList) {
329         defaultImportList.forEach(toscaImportByModel -> {
330             final Map<String, Object> existingImportYamlMap = new Yaml().load(toscaImportByModel.getContent());
331             final Map<String, Object> currentTypeYamlMap = (Map<String, Object>) existingImportYamlMap.get(elementTypeEnum.getToscaEntryName());
332             if (MapUtils.isNotEmpty(currentTypeYamlMap)) {
333                 typesYaml.keySet().forEach(currentTypeYamlMap::remove);
334             }
335             toscaImportByModel.setContent(new YamlUtil().objectToYaml(existingImportYamlMap));
336         });
337     }
338
339     private String buildAdditionalTypeDefinitionsContent(final ElementTypeEnum elementTypeEnum, final Map<String, Object> typesYamlMap,
340                                                          final Map<String, Object> originalContent) {
341         final Map<String, Object> originalTypeContent = (Map<String, Object>) originalContent.get(elementTypeEnum.getToscaEntryName());
342         if (MapUtils.isEmpty(originalTypeContent)) {
343             originalContent.put(elementTypeEnum.getToscaEntryName(), new LinkedHashMap<>(typesYamlMap));
344         } else {
345             originalTypeContent.putAll(typesYamlMap);
346         }
347         return new YamlUtil().objectToYaml(originalContent);
348     }
349
350     private String createAdditionalTypeDefinitionsHeader() {
351         return "tosca_definitions_version: tosca_simple_yaml_1_3" + "\n"
352             + "description: Auto-generated file that contains package custom types or types added after system installation." + "\n";
353     }
354
355     /**
356      * Deletes the given model if it exists, along with its MODEL_ELEMENT edges and import files.
357      *
358      * @param model         the model
359      * @param inTransaction if the operation is called in the middle of a janusgraph transaction
360      */
361     public void deleteModel(final Model model, final boolean inTransaction) {
362         boolean rollback = false;
363
364         try {
365             final GraphVertex modelVertexByName = findModelVertexByName(model.getName()).orElse(null);
366             if (modelVertexByName == null) {
367                 return;
368             }
369             toscaModelImportCassandraDao.deleteAllByModel(model.getName());
370             modelElementOperation.deleteModelElements(model, inTransaction);
371             deleteModel(model);
372         } catch (final OperationException e) {
373             rollback = true;
374             throw e;
375         } catch (final Exception e) {
376             rollback = true;
377             throw new OperationException(e, ActionStatus.COULD_NOT_DELETE_MODEL, model.getName());
378         } finally {
379             if (!inTransaction) {
380                 if (rollback) {
381                     janusGraphGenericDao.rollback();
382                 } else {
383                     janusGraphGenericDao.commit();
384                 }
385             }
386         }
387     }
388
389     private void deleteModel(final Model model) {
390         final var modelData = new ModelData(model.getName(), UniqueIdBuilder.buildModelUid(model.getName()), model.getModelType());
391         final Either<ModelData, JanusGraphOperationStatus> deleteParentNodeByModel = janusGraphGenericDao.deleteNode(modelData, ModelData.class);
392         if (deleteParentNodeByModel.isRight()) {
393             final var janusGraphOperationStatus = deleteParentNodeByModel.right().value();
394             log.error(EcompLoggerErrorCode.DATA_ERROR, ModelOperation.class.getName(),
395                 "Failed to delete model {} on JanusGraph with status {}", model.getName(), janusGraphOperationStatus);
396             throw new OperationException(ActionStatus.COULD_NOT_DELETE_MODEL, model.getName());
397         }
398     }
399
400     @Autowired
401     public void setModelElementOperation(final ModelElementOperation modelElementOperation) {
402         this.modelElementOperation = modelElementOperation;
403     }
404
405     @SuppressWarnings("unchecked")
406     public void updateTypesInAdditionalTypesImport(final ElementTypeEnum elementTypeEnum, final String typesYaml, final String modelName) {
407         final Optional<ToscaImportByModel> additionalTypeDefinitionsImportOptional = getAdditionalTypes(modelName);
408
409         if (additionalTypeDefinitionsImportOptional.isPresent()) {
410
411             final Map<String, Object> existingTypeContent = getExistingTypes(elementTypeEnum, additionalTypeDefinitionsImportOptional.get());
412             final Set<String> existingTypeNames = existingTypeContent.keySet();
413
414             Map<String, Object> newTypesYaml = new Yaml().load(typesYaml);
415             if (newTypesYaml.containsKey(DATA_TYPES.getElementName())) {
416                 newTypesYaml = (Map<String, Object>) newTypesYaml.get(DATA_TYPES.getElementName());
417             }
418             final Map<String, Object> typesToUpate = new HashMap<>();
419             newTypesYaml.entrySet().stream().filter(entry -> existingTypeNames.contains(entry.getKey())).forEach(newTypeToUpdate -> {
420
421                 final Map<String, Object> propertiesInNewDef =
422                     (Map<String, Object>) ((Map<String, Object>) newTypeToUpdate.getValue()).get(PROPERTIES.getElementName());
423                 final Map<String, Object> existingProperties =
424                     (Map<String, Object>) ((Map<String, Object>) existingTypeContent.get(newTypeToUpdate.getKey())).get(PROPERTIES.getElementName());
425
426                 final List<Entry<String, Object>> propertiesMissingFromNewDef = MapUtils.isEmpty(existingProperties) ? Collections.emptyList() :
427                     existingProperties.entrySet().stream()
428                         .filter(existingPropEntry -> !propertiesInNewDef.keySet().contains(existingPropEntry.getKey())).collect(Collectors.toList());
429
430                 if (CollectionUtils.isNotEmpty(propertiesMissingFromNewDef)) {
431                     typesToUpate.put(newTypeToUpdate.getKey(), newTypeToUpdate.getValue());
432
433                     propertiesMissingFromNewDef
434                         .forEach(existingPropToAdd -> propertiesInNewDef.put(existingPropToAdd.getKey(), existingPropToAdd.getValue()));
435                 }
436             });
437             if (MapUtils.isNotEmpty(typesToUpate)) {
438                 addTypesToDefaultImports(elementTypeEnum, new Yaml().dumpAsMap(typesToUpate), modelName);
439             }
440         }
441     }
442
443     private Optional<ToscaImportByModel> getAdditionalTypes(final String modelName) {
444         final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName);
445         return modelImportList.stream().filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny();
446     }
447
448     private Map<String, Object> getExistingTypes(final ElementTypeEnum elementTypeEnum, final ToscaImportByModel additionalTypeDefinitionsImport) {
449         final Map<String, Object> existingContent = new Yaml().load(additionalTypeDefinitionsImport.getContent());
450         return (Map<String, Object>) existingContent.get(elementTypeEnum.getToscaEntryName());
451     }
452
453     public void updatePropertyInAdditionalType(final ElementTypeEnum elementTypeEnum, final PropertyDefinitionDto property,
454                                                final String modelName, final String name, boolean isAdd) {
455         final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName);
456         final Optional<ToscaImportByModel> additionalTypeDefinitionsImportOptional = modelImportList.stream()
457             .filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny();
458         if (additionalTypeDefinitionsImportOptional.isEmpty()) {
459             return;
460         }
461         final ToscaImportByModel additionalTypeDefinitionsImport = additionalTypeDefinitionsImportOptional.get();
462         final List<ToscaImportByModel> rebuiltModelImportList = modelImportList.stream()
463             .filter(toscaImportByModel -> !ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(toscaImportByModel.getFullPath())))
464             .collect(Collectors.toList());
465         final Map<String, Object> originalContent = new Yaml().load(additionalTypeDefinitionsImport.getContent());
466         additionalTypeDefinitionsImport.setContent(
467             buildPropertyAdditionalTypeDefinitionContent(elementTypeEnum, name, property, originalContent, isAdd));
468         rebuiltModelImportList.add(additionalTypeDefinitionsImport);
469         toscaModelImportCassandraDao.saveAll(modelName, rebuiltModelImportList);
470     }
471
472     public void removeTypeFromAdditionalType(final ElementTypeEnum elementTypeEnum, final String modelName, final String name) {
473         final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName);
474         final Optional<ToscaImportByModel> additionalTypeDefinitionsImportOptional = modelImportList.stream()
475             .filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny();
476         if (additionalTypeDefinitionsImportOptional.isEmpty()) {
477             return;
478         }
479         final ToscaImportByModel additionalTypeDefinitionsImport = additionalTypeDefinitionsImportOptional.get();
480         removeExistingTypesFromDefaultImports(elementTypeEnum, Collections.singletonMap(name, null),
481             Collections.singletonList(additionalTypeDefinitionsImport));
482         final List<ToscaImportByModel> rebuiltModelImportList = modelImportList.stream()
483             .filter(toscaImportByModel -> !ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(toscaImportByModel.getFullPath())))
484             .collect(Collectors.toList());
485         rebuiltModelImportList.add(additionalTypeDefinitionsImport);
486         toscaModelImportCassandraDao.saveAll(modelName, rebuiltModelImportList);
487     }
488
489     private String buildPropertyAdditionalTypeDefinitionContent(final ElementTypeEnum elementTypeEnum, final String name,
490                                                                 final PropertyDefinitionDto property, final Map<String, Object> originalContent,
491                                                                 boolean isAdd) {
492         final Map<String, Object> originalTypeContent = (Map<String, Object>) originalContent.get(elementTypeEnum.getToscaEntryName());
493         Map<String, Object> typeContent = (Map<String, Object>) originalTypeContent.get(name);
494         Map<String, Object> typeProperties = (Map<String, Object>) typeContent.get(PROPERTIES.getElementName());
495         if (MapUtils.isEmpty(typeProperties)) {
496             typeProperties = new HashMap<>();
497         }
498         if (isAdd) {
499             typeProperties.put(property.getName(), constructProperty(property));
500         } else {
501             typeProperties.remove(property.getName());
502         }
503         typeContent.put(PROPERTIES.getElementName(), typeProperties);
504         return new YamlUtil().objectToYaml(originalContent);
505     }
506
507     private Map<String, Object> constructProperty(final PropertyDefinitionDto property) {
508         Map<String, Object> typeProp = new HashMap<>();
509         if (property.getType() != null) {
510             typeProp.put(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName(), property.getType());
511         }
512         if (property.getDescription() != null) {
513             typeProp.put(TypeUtils.ToscaTagNamesEnum.DESCRIPTION.getElementName(), property.getDescription());
514         }
515         Map<String, Object> schema = new HashMap<>();
516         if (property.getSchemaType() != null) {
517             schema.put(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName(), property.getSchemaType());
518             typeProp.put(TypeUtils.ToscaTagNamesEnum.ENTRY_SCHEMA.getElementName(), schema);
519         }
520         if (property.getDefaultValue() != null) {
521             typeProp.put(TypeUtils.ToscaTagNamesEnum.DEFAULT.getElementName(), property.getDefaultValue());
522         }
523         if (property.getRequired() != null) {
524             typeProp.put(TypeUtils.ToscaTagNamesEnum.REQUIRED.getElementName(), property.getRequired());
525         }
526         if (property.getConstraints() != null) {
527             typeProp.put(TypeUtils.ToscaTagNamesEnum.CONSTRAINTS.getElementName(), getPropertyConstraintsValues(property.getConstraints()));
528         }
529         return typeProp;
530     }
531
532     private List<Object> getPropertyConstraintsValues(final List<Object> propertyConstraints) {
533         List<Object> constraints = new ArrayList<>();
534         for (Object constraint : propertyConstraints) {
535             Map<String, Object> constraintsMap = new HashMap<>();
536             PropertyConstraint propertyConstraint = (PropertyConstraint) constraint;
537             Object value = null;
538             if (constraint instanceof EqualConstraint) {
539                 value = ((EqualConstraint) constraint).getEqual();
540             } else if (constraint instanceof GreaterThanConstraint) {
541                 value = ((GreaterThanConstraint) constraint).getGreaterThan();
542             } else if (constraint instanceof GreaterOrEqualConstraint) {
543                 value = ((GreaterOrEqualConstraint) constraint).getGreaterOrEqual();
544             } else if (constraint instanceof LessThanConstraint) {
545                 value = ((LessThanConstraint) constraint).getLessThan();
546             } else if (constraint instanceof LessOrEqualConstraint) {
547                 value = ((LessOrEqualConstraint) constraint).getLessOrEqual();
548             } else if (constraint instanceof InRangeConstraint) {
549                 value = ((InRangeConstraint) constraint).getInRange();
550             } else if (constraint instanceof ValidValuesConstraint) {
551                 value = ((ValidValuesConstraint) constraint).getValidValues();
552             } else if (constraint instanceof LengthConstraint) {
553                 value = ((LengthConstraint) constraint).getLength();
554             } else if (constraint instanceof MinLengthConstraint) {
555                 value = ((MinLengthConstraint) constraint).getMinLength();
556             } else if (constraint instanceof MaxLengthConstraint) {
557                 value = ((MaxLengthConstraint) constraint).getMaxLength();
558             } else if (constraint instanceof PatternConstraint) {
559                 value = ((PatternConstraint) constraint).getPattern();
560             }
561             constraintsMap.put(propertyConstraint.getConstraintType().getType(), value);
562             constraints.add(constraintsMap);
563         }
564         return constraints;
565     }
566
567 }