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