Fix issue in artifact type update
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / operations / impl / ArtifactTypeOperation.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 fj.data.Either;
23 import org.apache.commons.lang3.StringUtils;
24 import org.apache.commons.lang3.tuple.ImmutablePair;
25 import org.openecomp.sdc.be.dao.api.ActionStatus;
26 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
27 import org.openecomp.sdc.be.dao.graph.datatype.GraphNode;
28 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
29 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
30 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
31 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
32 import org.openecomp.sdc.be.datatypes.elements.ArtifactTypeDataDefinition;
33 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
34 import org.openecomp.sdc.be.model.ArtifactTypeDefinition;
35 import org.openecomp.sdc.be.model.PropertyDefinition;
36 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ModelOperationExceptionSupplier;
37 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
38 import org.openecomp.sdc.be.model.operations.api.DerivedFromOperation;
39 import org.openecomp.sdc.be.model.operations.api.IArtifactTypeOperation;
40 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
41 import org.openecomp.sdc.be.resources.data.ArtifactTypeData;
42 import org.openecomp.sdc.be.resources.data.ModelData;
43 import org.openecomp.sdc.be.resources.data.PropertyData;
44 import org.openecomp.sdc.be.resources.data.UniqueIdData;
45 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
46 import org.openecomp.sdc.common.log.wrappers.Logger;
47 import org.springframework.beans.factory.annotation.Autowired;
48 import org.springframework.stereotype.Component;
49
50 import java.util.*;
51 import java.util.stream.Collectors;
52
53
54 /**
55  * This class is responsible for handling all operations for the TOSCA artifact types
56  */
57 @Component("artifact-type-operation")
58 public class ArtifactTypeOperation extends AbstractOperation implements IArtifactTypeOperation {
59
60     private static final Logger LOGGER = Logger.getLogger(ArtifactTypeOperation.class.getName());
61
62     private final PropertyOperation propertyOperation;
63     private final DerivedFromOperation derivedFromOperation;
64     private final ModelOperation modelOperation;
65
66     @Autowired
67     public ArtifactTypeOperation(final PropertyOperation propertyOperation,
68                                  final DerivedFromOperation derivedFromOperation,
69                                  final ModelOperation modelOperation) {
70         this.propertyOperation = propertyOperation;
71         this.derivedFromOperation = derivedFromOperation;
72         this.modelOperation = modelOperation;
73     }
74
75     /**
76      * Creates a TOSCA artifact types
77      * @param artifactType the TOSCA artifact types definition to be created
78      * @return the created TOSCA artifact types definition
79      */
80     @Override
81     public ArtifactTypeDefinition createArtifactType(final ArtifactTypeDefinition artifactType) {
82         return createArtifactType(artifactType, false);
83     }
84
85     @Override
86     public ArtifactTypeDefinition createArtifactType(final ArtifactTypeDefinition artifactType,
87                                                      final boolean inTransaction) {
88         Either<ArtifactTypeDefinition, StorageOperationStatus> createNodeResult = null;
89         try {
90             artifactType.setUniqueId(UniqueIdBuilder.buildArtifactTypeUid(artifactType.getModel(), artifactType.getType()));
91             final ArtifactTypeData artifactTypeData = new ArtifactTypeData(artifactType);
92             final Either<ArtifactTypeData, JanusGraphOperationStatus> existArtifact = janusGraphGenericDao
93                 .getNode(artifactTypeData.getUniqueIdKey(), artifactTypeData.getUniqueId(), ArtifactTypeData.class);
94             if (!existArtifact.isLeft()) {
95                 LOGGER.debug("Artifact type did not exist, creating new one {}", artifactType);
96                 createNodeResult = janusGraphGenericDao.createNode(artifactTypeData, ArtifactTypeData.class).right()
97                         .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus).left()
98                         .map(createdDerivedFrom -> artifactType);
99                 addPropertiesToArtifactType(artifactType);
100                 addModelRelation(artifactType);
101                 addDerivedFromRelation(artifactType);
102             }
103             else {
104                 LOGGER.debug("Artifact type {} already exists", artifactType);
105                 createNodeResult = janusGraphGenericDao.updateNode(artifactTypeData, ArtifactTypeData.class).right()
106                         .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus).left()
107                         .bind(updatedNode -> updateArtifactProperties(artifactType.getUniqueId(), artifactType.getProperties())).left()
108                         .bind(updatedProperties -> updateArtifactDerivedFrom(artifactType)).left()
109                         .map(updatedDerivedFrom -> artifactType);
110             }
111             if (createNodeResult.isRight()) {
112                 final StorageOperationStatus operationStatus = createNodeResult.right().value();
113                 LOGGER.error(EcompLoggerErrorCode.DATA_ERROR,
114                     "Failed to add artifact type {} to graph. Operation status {}", artifactType.getType(), operationStatus);
115                 throw new OperationException(ActionStatus.GENERAL_ERROR,
116                     String.format("Failed to create artifact type %s with status %s", artifactType.getType(),
117                         operationStatus));
118             }
119             return createNodeResult.left().value();
120
121         } finally {
122             if (!inTransaction) {
123                 if (createNodeResult == null || createNodeResult.isRight()) {
124                     LOGGER.debug("Rollback on graph.");
125                     janusGraphGenericDao.rollback();
126                 } else {
127                     janusGraphGenericDao.commit();
128                 }
129             }
130         }
131     }
132
133     /**
134      * Finds all TOSCA artifact types applicable to the given model name
135      * @param model model name
136      * @return all the TOSCA artifact types found
137      */
138     @Override
139     public Map<String, ArtifactTypeDefinition> getAllArtifactTypes(final String model) {
140         final Either<List<ArtifactTypeData>, JanusGraphOperationStatus> artifactTypes =
141             janusGraphGenericDao.getByCriteriaForModel(NodeTypeEnum.ArtifactType, Collections.emptyMap(), model, ArtifactTypeData.class);
142         if (artifactTypes.isRight()) {
143             if (JanusGraphOperationStatus.NOT_FOUND == artifactTypes.right().value()) {
144                 return Collections.emptyMap();
145             }
146             throw new OperationException(ActionStatus.GENERAL_ERROR,
147                 String.format("Failed to find artifact on JanusGraph with status %s",
148                     DaoStatusConverter.convertJanusGraphStatusToStorageStatus(artifactTypes.right().value())));
149         }
150         final Map<String, ArtifactTypeDefinition> artifactTypeDefinitionTypes = new HashMap<>();
151         final List<ArtifactTypeDefinition> artifactTypeList = artifactTypes.left().value().stream()
152             .map(this::convertArtifactDataDefinition)
153             .filter(artifactTypeDefinition -> artifactTypeDefinition.getUniqueId().equalsIgnoreCase(UniqueIdBuilder
154                 .buildArtifactTypeUid(artifactTypeDefinition.getModel(), artifactTypeDefinition.getType())))
155             .collect(Collectors.toList());
156         for (final ArtifactTypeDefinition type : artifactTypeList) {
157             artifactTypeDefinitionTypes.put(type.getUniqueId(), type);
158         }
159         return artifactTypeDefinitionTypes;
160     }
161
162     private Either<Map<String, PropertyData>, StorageOperationStatus> updateArtifactProperties(final String artifactId, final List<PropertyDefinition> properties) {
163         LOGGER.debug("#updateArtifactProperties - updating artifact type properties for artifact type with id {}", artifactId);
164         return propertyOperation.deletePropertiesAssociatedToNode(NodeTypeEnum.ArtifactType, artifactId).left()
165                 .bind(deleteProps -> addPropertiesToArtifact(artifactId, properties));
166     }
167
168     private Either<GraphRelation, StorageOperationStatus> updateArtifactDerivedFrom(ArtifactTypeDefinition updatedArtifactType) {
169         String artifactTypeId = updatedArtifactType.getUniqueId();
170         
171         Either<ArtifactTypeData, StorageOperationStatus> currentDerivedFrom = derivedFromOperation.getDerivedFromChild(updatedArtifactType.getUniqueId(), NodeTypeEnum.ArtifactType, ArtifactTypeData.class);
172         LOGGER.debug(
173                 "#updateArtifactDerivedFrom - updating artifact derived from relation for artifact type with id {}. old derived type {}. new derived type {}",
174                 artifactTypeId, currentDerivedFrom.isLeft() ? currentDerivedFrom: "", updatedArtifactType.getDerivedFrom());
175         if (currentDerivedFrom.isLeft()) {
176             StorageOperationStatus deleteDerivedRelationStatus = deleteDerivedFromArtifactType(artifactTypeId, currentDerivedFrom.left().value().getArtifactTypeDataDefinition().getType(), updatedArtifactType.getModel());
177             if (deleteDerivedRelationStatus != StorageOperationStatus.OK) {
178                 return Either.right(deleteDerivedRelationStatus);
179             }
180         }
181         return addDerivedFromRelation(updatedArtifactType, artifactTypeId);
182     }
183
184     private StorageOperationStatus deleteDerivedFromArtifactType(String artifactTypeId, String derivedFromType, String model) {
185         if (derivedFromType == null) {
186             return StorageOperationStatus.OK;
187         }
188         LOGGER.debug("#deleteDerivedFromArtifactType - deleting derivedFrom relation for artifact type with id {} and its derived type {}", artifactTypeId,
189                 derivedFromType);
190         return getProjectionLatestArtifactTypeByType(derivedFromType, model).either(
191                 derivedFromNode -> derivedFromOperation.removeDerivedFromRelation(artifactTypeId, derivedFromNode.getUniqueId(), NodeTypeEnum.ArtifactType),
192                 err -> err);
193     }
194
195     private Either<Map<String, PropertyData>, StorageOperationStatus> addPropertiesToArtifact(String artifactId,
196                                                                                             List<PropertyDefinition> properties) {
197         LOGGER.debug("#addPropertiesToArtifact - adding artifact type properties for artifact type with id {}", artifactId);
198         return propertyOperation.addPropertiesToElementType(artifactId, NodeTypeEnum.ArtifactType, properties).right()
199                 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
200     }
201
202     /**
203      * Coverts the given artifact type data into a TOSCA artifact types definition
204      * @param artifactTypeData artifact type data representation
205      * @return the TOSCA artifact types definition
206      */
207     private ArtifactTypeDefinition convertArtifactDataDefinition(final ArtifactTypeData artifactTypeData) {
208         LOGGER.debug("The object returned after create tosca artifact type is {}", artifactTypeData);
209         final ArtifactTypeDefinition artifactType = new ArtifactTypeDefinition(artifactTypeData.getArtifactTypeDataDefinition());
210         final var modelAssociatedToArtifactOptional = getModelAssociatedToArtifact(artifactTypeData.getUniqueId());
211         if (!modelAssociatedToArtifactOptional.isEmpty()) {
212             artifactType.setModel(modelAssociatedToArtifactOptional.get());
213         }
214         artifactType.setType(artifactTypeData.getArtifactTypeDataDefinition().getType());
215         final ArtifactTypeData derivedFromNode = fillDerivedFrom(artifactType);
216         fillProperties(artifactType, derivedFromNode);
217         return artifactType;
218     }
219
220     /**
221      * Finds an artifact type data on JanusGraph based on the given parameters
222      * @param type the artifact type derived from
223      * @param model the model name
224      * @return the optional artifact type data found
225      */
226     private Optional<ArtifactTypeData> getLatestArtifactTypeByType(final String type, final String model) {
227         final Map<String, Object> mapCriteria = new HashMap<>();
228         mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
229         final Either<List<ArtifactTypeData>, JanusGraphOperationStatus> result = janusGraphGenericDao.getByCriteriaForModel(NodeTypeEnum.ArtifactType,
230             mapCriteria, model, ArtifactTypeData.class);
231         if (result.isRight()) {
232             final JanusGraphOperationStatus status = result.right().value();
233             if (JanusGraphOperationStatus.NOT_FOUND == status) {
234                 return Optional.empty();
235             }
236             throw new OperationException(ActionStatus.GENERAL_ERROR,
237                 String.format("Failed to find artifact by type on JanusGraph with status %s",
238                     DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status)));
239         }
240         return Optional.of(result.left().value().get(0));
241     }
242
243     private Either<ArtifactTypeDefinition, StorageOperationStatus> getProjectionLatestArtifactTypeByType(String type, String model) {
244         Map<String, Object> mapCriteria = new HashMap<>();
245         mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
246         return getArtifactTypeByCriteria(type, mapCriteria, model);
247     }
248
249     /**
250      * Creates the derivedFrom relation for the given TOSCA artifact types
251      * @param artifactType the TOSCA artifact types definition
252      */
253     private void addDerivedFromRelation(final ArtifactTypeDefinition artifactType) {
254         final String derivedFrom = artifactType.getDerivedFrom();
255         final String artifactId = artifactType.getUniqueId();
256         if (derivedFrom == null || derivedFrom.isEmpty()) {
257             return;
258         }
259         final var getArtifactTypeOptional = getLatestArtifactTypeByType(derivedFrom, artifactType.getModel());
260         if (getArtifactTypeOptional.isPresent()) {
261             if (derivedFromOperation.addDerivedFromRelation(artifactId, getArtifactTypeOptional.get().getUniqueId(),
262                 NodeTypeEnum.ArtifactType).isRight()) {
263                 throw new OperationException(ActionStatus.GENERAL_ERROR,
264                     String.format("Failed creating derivedFrom relation for artifact type %s", artifactType.getType()));
265             }
266         }
267     }
268
269     private Either<GraphRelation, StorageOperationStatus> addDerivedFromRelation(ArtifactTypeDefinition artifactType, String atUniqueId) {
270         String derivedFrom = artifactType.getDerivedFrom();
271         if (derivedFrom == null) {
272             return Either.left(null);
273         }
274         LOGGER.debug("#addDerivedFromRelationBefore - adding derived from relation between artifact type {} to its parent {}", artifactType.getType(),
275                 derivedFrom);
276         return this.getProjectionLatestArtifactTypeByType(derivedFrom, artifactType.getModel()).left().bind(
277                 derivedFromArtifact -> derivedFromOperation.addDerivedFromRelation(atUniqueId, derivedFromArtifact.getUniqueId(), NodeTypeEnum.ArtifactType));
278     }
279
280     private Either<ArtifactTypeDefinition, StorageOperationStatus> getArtifactTypeByCriteria(String type, Map<String, Object> properties, String model) {
281         Either<ArtifactTypeDefinition, StorageOperationStatus> result;
282         if (type == null || type.isEmpty()) {
283             LOGGER.error("type is empty");
284             result = Either.right(StorageOperationStatus.INVALID_ID);
285             return result;
286         }
287         Either<List<ArtifactTypeData>, JanusGraphOperationStatus> eitherArtifactData = janusGraphGenericDao
288                 .getByCriteriaForModel(NodeTypeEnum.ArtifactType, properties, model, ArtifactTypeData.class);
289         if (eitherArtifactData.isRight()) {
290             result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(eitherArtifactData.right().value()));
291         } else {
292             ArtifactTypeDataDefinition dataDefinition = eitherArtifactData.left().value().stream().map(ArtifactTypeData::getArtifactTypeDataDefinition)
293                     .findFirst().get();
294             result = getArtifactTypeByUid(dataDefinition.getUniqueId());
295         }
296         return result;
297     }
298
299     private Either<ArtifactTypeDefinition, StorageOperationStatus> getArtifactTypeByUid(String uniqueId) {
300         LOGGER.debug("#getArtifactTypeByUid - fetching artifact type with id {}", uniqueId);
301         return janusGraphGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ArtifactType), uniqueId, ArtifactTypeData.class).right()
302                 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus).left()
303                 .bind(artifactType -> createArtifactTypeDefinition(uniqueId, artifactType));
304     }
305
306     private Either<ArtifactTypeDefinition, StorageOperationStatus> createArtifactTypeDefinition(String uniqueId, ArtifactTypeData artifactTypeNode) {
307         ArtifactTypeDefinition artifactType = new ArtifactTypeDefinition(artifactTypeNode.getArtifactTypeDataDefinition());
308         Optional<String> modelName = getAssociatedModelName(uniqueId);
309         if (modelName.isPresent()) {
310             artifactType.setModel(modelName.get());
311         }
312         return fillDerivedFrom(uniqueId, artifactType).left().map(derivedFrom -> fillProperties(uniqueId, artifactType, derivedFrom)).left()
313                 .map(props -> artifactType);
314     }
315
316     private Optional<String> getAssociatedModelName(String uniqueId) {
317         final Either<ImmutablePair<ModelData, GraphEdge>, JanusGraphOperationStatus> modelName = janusGraphGenericDao.getParentNode(
318                 UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ArtifactType), uniqueId, GraphEdgeLabels.MODEL_ELEMENT,
319                 NodeTypeEnum.Model, ModelData.class);
320         if (modelName.isRight()) {
321             return Optional.empty();
322         }
323         return Optional.ofNullable(modelName.left().value().getLeft().getName());
324     }
325
326     /**
327      * Adds a property definition to the given TOSCA artifact types definition
328      * @param artifactType the TOSCA artifact types
329      */
330     private void addPropertiesToArtifactType(final ArtifactTypeDefinition artifactType) {
331         final List<PropertyDefinition> properties = artifactType.getProperties();
332         final Either<Map<String, PropertyData>, JanusGraphOperationStatus> addPropertiesToArtifactType =
333             propertyOperation.addPropertiesToElementType(artifactType.getUniqueId(), NodeTypeEnum.ArtifactType, properties);
334         if (addPropertiesToArtifactType.isRight()) {
335             throw new OperationException(ActionStatus.GENERAL_ERROR,
336                 String.format("Failed creating properties for artifact type %s with status %s",
337                     artifactType.getType(), DaoStatusConverter.convertJanusGraphStatusToStorageStatus(addPropertiesToArtifactType.right().value())));
338         }
339     }
340
341     /**
342      * Creates an edge between the given TOSCA artifact types and it`s model
343      * @param artifactType the TOSCA artifact types
344      */
345     private void addModelRelation(final ArtifactTypeDefinition artifactType) {
346         final String model = artifactType.getModel();
347         if (StringUtils.isNotEmpty(model)) {
348             final GraphNode from = new UniqueIdData(NodeTypeEnum.Model, UniqueIdBuilder.buildModelUid(model));
349             final GraphNode to = new UniqueIdData(NodeTypeEnum.ArtifactType, artifactType.getUniqueId());
350             LOGGER.info("Connecting model {} to type {}", from, to);
351             final Either<GraphRelation, JanusGraphOperationStatus> status = janusGraphGenericDao.createRelation(from,
352                 to, GraphEdgeLabels.MODEL_ELEMENT, Collections.emptyMap());
353             if (status.isRight()) {
354                 throw new OperationException(ActionStatus.GENERAL_ERROR,
355                     String.format("Failed creating relation between model %s and artifact type %s with status %s",
356                         model, artifactType.getType(), DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status.right().value())));
357             }
358         }
359     }
360
361     /**
362      * Finds a model associated to the given artifact type unique id
363      * @param uid the TOSCA artifact types unique id
364      * @return
365      */
366     private Optional<String> getModelAssociatedToArtifact(final String uid) {
367         final Either<ImmutablePair<ModelData, GraphEdge>, JanusGraphOperationStatus> model =
368             janusGraphGenericDao.getParentNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Interface), uid,
369                 GraphEdgeLabels.MODEL_ELEMENT, NodeTypeEnum.Model, ModelData.class);
370         if (model.isLeft()) {
371             return Optional.ofNullable(model.left().value().getLeft().getName());
372         }
373         return Optional.empty();
374     }
375
376     /**
377      * Finds the derived from for teh given TOSCA artifact types
378      * @param artifactType
379      * @return
380      */
381     private ArtifactTypeData fillDerivedFrom(final ArtifactTypeDefinition artifactType) {
382         final Either<ArtifactTypeData, StorageOperationStatus> result = derivedFromOperation
383             .getDerivedFromChild(artifactType.getUniqueId(), NodeTypeEnum.ArtifactType, ArtifactTypeData.class)
384             .right().bind(this::handleDerivedFromNotExist).left()
385             .map(derivedFrom -> setDerivedFrom(artifactType, derivedFrom));
386         if (result.isRight()) {
387             throw new OperationException(ActionStatus.GENERAL_ERROR,
388                 String.format("Failed fetching derivedFrom for artifact type %s with status %s",
389                     artifactType.getType(), result.right().value()));
390         }
391         return result.left().value();
392     }
393
394     private Either<ArtifactTypeData, StorageOperationStatus> fillDerivedFrom(String uniqueId, ArtifactTypeDefinition artifactType) {
395         LOGGER.debug("#fillDerivedFrom - fetching artifact type {} derived node", artifactType.getType());
396         return derivedFromOperation.getDerivedFromChild(uniqueId, NodeTypeEnum.ArtifactType, ArtifactTypeData.class).right()
397                 .bind(this::handleDerivedFromNotExist).left().map(derivedFrom -> setDerivedFrom(artifactType, derivedFrom));
398     }
399
400     private Either<ArtifactTypeData, StorageOperationStatus> handleDerivedFromNotExist(final StorageOperationStatus storageOperationStatus) {
401         if (storageOperationStatus == StorageOperationStatus.NOT_FOUND) {
402             return Either.left(null);
403         }
404         return Either.right(storageOperationStatus);
405     }
406
407     private ArtifactTypeData setDerivedFrom(final ArtifactTypeDefinition artifactType, final ArtifactTypeData derivedFrom) {
408         if (derivedFrom != null) {
409             artifactType.setDerivedFrom(derivedFrom.getArtifactTypeDataDefinition().getType());
410         }
411         return derivedFrom;
412     }
413
414     /**
415      * Finds all properties for the given TOSCA artifact types
416      * @param artifactType the TOSCA artifact types
417      * @param derivedFromNode the TOSCA artifact types derived from
418      */
419     private void fillProperties(final ArtifactTypeDefinition artifactType, final ArtifactTypeData derivedFromNode) {
420         final Either<List<PropertyDefinition>, StorageOperationStatus> result =
421             propertyOperation.findPropertiesOfNode(NodeTypeEnum.ArtifactType, artifactType.getUniqueId()).right()
422                 .bind(this::handleNoProperties).left().bind(propsMap -> fillDerivedFromProperties(artifactType,
423                     derivedFromNode, new ArrayList<>(propsMap.values())));
424         if (result.isRight()) {
425             throw new OperationException(ActionStatus.GENERAL_ERROR,
426                 String.format("Failed fetching properties for artifact type %s with status %s",
427                     artifactType.getType(), result.right().value()));
428         }
429     }
430
431     private Either<List<PropertyDefinition>, StorageOperationStatus> fillProperties(String uniqueId, ArtifactTypeDefinition artifactType,
432                                                                                     ArtifactTypeData derivedFromNode) {
433         LOGGER.debug("#fillProperties - fetching all properties for artifact type {}", artifactType.getType());
434         return propertyOperation.findPropertiesOfNode(NodeTypeEnum.ArtifactType, uniqueId).right().bind(this::handleArtifactTypeHasNoProperties).left()
435                 .bind(propsMap -> fillDerivedFromProperties(artifactType, derivedFromNode, new ArrayList<>(propsMap.values())));
436     }
437
438     private Either<Map<String, PropertyDefinition>, StorageOperationStatus> handleArtifactTypeHasNoProperties(JanusGraphOperationStatus err) {
439         if (err == JanusGraphOperationStatus.NOT_FOUND) {
440             return Either.left(new HashMap<>());
441         }
442         return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(err));
443     }
444
445     private Either<Map<String, PropertyDefinition>, StorageOperationStatus> handleNoProperties(
446         final JanusGraphOperationStatus janusGraphOperationStatus) {
447         if (janusGraphOperationStatus == JanusGraphOperationStatus.NOT_FOUND) {
448             return Either.left(new HashMap<>());
449         }
450         return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(janusGraphOperationStatus));
451     }
452
453     private Either<List<PropertyDefinition>, StorageOperationStatus> fillDerivedFromProperties(final ArtifactTypeDefinition artifactType,
454                                                                                                final ArtifactTypeData derivedFromNode,
455                                                                                                final List<PropertyDefinition> artifactTypeProperties)
456     {
457         if (derivedFromNode == null) {
458             artifactType.setProperties(artifactTypeProperties);
459             return Either.left(artifactTypeProperties);
460         }
461         return propertyOperation
462             .getAllPropertiesRec(derivedFromNode.getUniqueId(), NodeTypeEnum.ArtifactType, ArtifactTypeData.class)
463             .left().map(derivedFromProps -> {
464                 artifactTypeProperties.addAll(derivedFromProps);
465                 return artifactTypeProperties;
466             }).left().map(allProps -> {
467                 artifactType.setProperties(allProps);
468                 return allProps;
469             });
470     }
471
472     /**
473      * The Model field is an optional entry when uploading a resource. If the field is present, it validates if the Model name exists.
474      * @param modelName Model names declared on the resource json representation
475      */
476     public void validateModel(final String modelName) {
477         if (modelOperation.findModelByName(modelName).isEmpty()) {
478             LOGGER.error(EcompLoggerErrorCode.DATA_ERROR,"Could not find model name {}", modelName);
479             throw ModelOperationExceptionSupplier.invalidModel(modelName).get();
480         }
481     }
482 }