d16a7353cb400dc2135db994e751b1615d760d5f
[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, artifactType.getDerivedFrom())).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 currDerivedFromArtifactType) {
170         String artifactTypeId = updatedArtifactType.getUniqueId();
171         LOGGER.debug(
172                 "#updateArtifactDerivedFrom - updating artifact derived from relation for artifact type with id {}. old derived type {}. new derived type {}",
173                 artifactTypeId, currDerivedFromArtifactType, updatedArtifactType.getDerivedFrom());
174         StorageOperationStatus deleteDerivedRelationStatus = deleteDerivedFromArtifactType(artifactTypeId, currDerivedFromArtifactType, updatedArtifactType.getModel());
175         if (deleteDerivedRelationStatus != StorageOperationStatus.OK) {
176             return Either.right(deleteDerivedRelationStatus);
177         }
178         return addDerivedFromRelation(updatedArtifactType, artifactTypeId);
179     }
180
181     private StorageOperationStatus deleteDerivedFromArtifactType(String artifactTypeId, String derivedFromType, String model) {
182         if (derivedFromType == null) {
183             return StorageOperationStatus.OK;
184         }
185         LOGGER.debug("#deleteDerivedFromArtifactType - deleting derivedFrom relation for artifact type with id {} and its derived type {}", artifactTypeId,
186                 derivedFromType);
187         return getProjectionLatestArtifactTypeByType(derivedFromType, model).either(
188                 derivedFromNode -> derivedFromOperation.removeDerivedFromRelation(artifactTypeId, derivedFromNode.getUniqueId(), NodeTypeEnum.ArtifactType),
189                 err -> err);
190     }
191
192     private Either<Map<String, PropertyData>, StorageOperationStatus> addPropertiesToArtifact(String artifactId,
193                                                                                             List<PropertyDefinition> properties) {
194         LOGGER.debug("#addPropertiesToArtifact - adding artifact type properties for artifact type with id {}", artifactId);
195         return propertyOperation.addPropertiesToElementType(artifactId, NodeTypeEnum.ArtifactType, properties).right()
196                 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
197     }
198
199     /**
200      * Coverts the given artifact type data into a TOSCA artifact types definition
201      * @param artifactTypeData artifact type data representation
202      * @return the TOSCA artifact types definition
203      */
204     private ArtifactTypeDefinition convertArtifactDataDefinition(final ArtifactTypeData artifactTypeData) {
205         LOGGER.debug("The object returned after create tosca artifact type is {}", artifactTypeData);
206         final ArtifactTypeDefinition artifactType = new ArtifactTypeDefinition(artifactTypeData.getArtifactTypeDataDefinition());
207         final var modelAssociatedToArtifactOptional = getModelAssociatedToArtifact(artifactTypeData.getUniqueId());
208         if (!modelAssociatedToArtifactOptional.isEmpty()) {
209             artifactType.setModel(modelAssociatedToArtifactOptional.get());
210         }
211         artifactType.setType(artifactTypeData.getArtifactTypeDataDefinition().getType());
212         final ArtifactTypeData derivedFromNode = fillDerivedFrom(artifactType);
213         fillProperties(artifactType, derivedFromNode);
214         return artifactType;
215     }
216
217     /**
218      * Finds an artifact type data on JanusGraph based on the given parameters
219      * @param type the artifact type derived from
220      * @param model the model name
221      * @return the optional artifact type data found
222      */
223     private Optional<ArtifactTypeData> getLatestArtifactTypeByType(final String type, final String model) {
224         final Map<String, Object> mapCriteria = new HashMap<>();
225         mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
226         final Either<List<ArtifactTypeData>, JanusGraphOperationStatus> result = janusGraphGenericDao.getByCriteriaForModel(NodeTypeEnum.ArtifactType,
227             mapCriteria, model, ArtifactTypeData.class);
228         if (result.isRight()) {
229             final JanusGraphOperationStatus status = result.right().value();
230             if (JanusGraphOperationStatus.NOT_FOUND == status) {
231                 return Optional.empty();
232             }
233             throw new OperationException(ActionStatus.GENERAL_ERROR,
234                 String.format("Failed to find artifact by type on JanusGraph with status %s",
235                     DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status)));
236         }
237         return Optional.of(result.left().value().get(0));
238     }
239
240     private Either<ArtifactTypeDefinition, StorageOperationStatus> getProjectionLatestArtifactTypeByType(String type, String model) {
241         Map<String, Object> mapCriteria = new HashMap<>();
242         mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
243         mapCriteria.put(GraphPropertiesDictionary.IS_HIGHEST_VERSION.getProperty(), true);
244         return getArtifactTypeByCriteria(type, mapCriteria, model);
245     }
246
247     /**
248      * Creates the derivedFrom relation for the given TOSCA artifact types
249      * @param artifactType the TOSCA artifact types definition
250      */
251     private void addDerivedFromRelation(final ArtifactTypeDefinition artifactType) {
252         final String derivedFrom = artifactType.getDerivedFrom();
253         final String artifactId = artifactType.getUniqueId();
254         if (derivedFrom == null || derivedFrom.isEmpty()) {
255             return;
256         }
257         final var getArtifactTypeOptional = getLatestArtifactTypeByType(derivedFrom, artifactType.getModel());
258         if (getArtifactTypeOptional.isPresent()) {
259             if (derivedFromOperation.addDerivedFromRelation(artifactId, getArtifactTypeOptional.get().getUniqueId(),
260                 NodeTypeEnum.ArtifactType).isRight()) {
261                 throw new OperationException(ActionStatus.GENERAL_ERROR,
262                     String.format("Failed creating derivedFrom relation for artifact type %s", artifactType.getType()));
263             }
264         }
265     }
266
267     private Either<GraphRelation, StorageOperationStatus> addDerivedFromRelation(ArtifactTypeDefinition artifactType, String atUniqueId) {
268         String derivedFrom = artifactType.getDerivedFrom();
269         if (derivedFrom == null) {
270             return Either.left(null);
271         }
272         LOGGER.debug("#addDerivedFromRelationBefore - adding derived from relation between artifact type {} to its parent {}", artifactType.getType(),
273                 derivedFrom);
274         return this.getProjectionLatestArtifactTypeByType(derivedFrom, artifactType.getModel()).left().bind(
275                 derivedFromArtifact -> derivedFromOperation.addDerivedFromRelation(atUniqueId, derivedFromArtifact.getUniqueId(), NodeTypeEnum.ArtifactType));
276     }
277
278     private Either<ArtifactTypeDefinition, StorageOperationStatus> getArtifactTypeByCriteria(String type, Map<String, Object> properties, String model) {
279         Either<ArtifactTypeDefinition, StorageOperationStatus> result;
280         if (type == null || type.isEmpty()) {
281             LOGGER.error("type is empty");
282             result = Either.right(StorageOperationStatus.INVALID_ID);
283             return result;
284         }
285         Either<List<ArtifactTypeData>, JanusGraphOperationStatus> eitherArtifactData = janusGraphGenericDao
286                 .getByCriteriaForModel(NodeTypeEnum.ArtifactType, properties, model, ArtifactTypeData.class);
287         if (eitherArtifactData.isRight()) {
288             result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(eitherArtifactData.right().value()));
289         } else {
290             ArtifactTypeDataDefinition dataDefinition = eitherArtifactData.left().value().stream().map(ArtifactTypeData::getArtifactTypeDataDefinition)
291                     .findFirst().get();
292             result = getArtifactTypeByUid(dataDefinition.getUniqueId());
293         }
294         return result;
295     }
296
297     private Either<ArtifactTypeDefinition, StorageOperationStatus> getArtifactTypeByUid(String uniqueId) {
298         LOGGER.debug("#getArtifactTypeByUid - fetching artifact type with id {}", uniqueId);
299         return janusGraphGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ArtifactType), uniqueId, ArtifactTypeData.class).right()
300                 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus).left()
301                 .bind(artifactType -> createArtifactTypeDefinition(uniqueId, artifactType));
302     }
303
304     private Either<ArtifactTypeDefinition, StorageOperationStatus> createArtifactTypeDefinition(String uniqueId, ArtifactTypeData artifactTypeNode) {
305         ArtifactTypeDefinition artifactType = new ArtifactTypeDefinition(artifactTypeNode.getArtifactTypeDataDefinition());
306         Optional<String> modelName = getAssociatedModelName(uniqueId);
307         if (modelName.isPresent()) {
308             artifactType.setModel(modelName.get());
309         }
310         return fillDerivedFrom(uniqueId, artifactType).left().map(derivedFrom -> fillProperties(uniqueId, artifactType, derivedFrom)).left()
311                 .map(props -> artifactType);
312     }
313
314     private Optional<String> getAssociatedModelName(String uniqueId) {
315         final Either<ImmutablePair<ModelData, GraphEdge>, JanusGraphOperationStatus> modelName = janusGraphGenericDao.getParentNode(
316                 UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ArtifactType), uniqueId, GraphEdgeLabels.MODEL_ELEMENT,
317                 NodeTypeEnum.Model, ModelData.class);
318         if (modelName.isRight()) {
319             return Optional.empty();
320         }
321         return Optional.ofNullable(modelName.left().value().getLeft().getName());
322     }
323
324     /**
325      * Adds a property definition to the given TOSCA artifact types definition
326      * @param artifactType the TOSCA artifact types
327      */
328     private void addPropertiesToArtifactType(final ArtifactTypeDefinition artifactType) {
329         final List<PropertyDefinition> properties = artifactType.getProperties();
330         final Either<Map<String, PropertyData>, JanusGraphOperationStatus> addPropertiesToArtifactType =
331             propertyOperation.addPropertiesToElementType(artifactType.getUniqueId(), NodeTypeEnum.ArtifactType, properties);
332         if (addPropertiesToArtifactType.isRight()) {
333             throw new OperationException(ActionStatus.GENERAL_ERROR,
334                 String.format("Failed creating properties for artifact type %s with status %s",
335                     artifactType.getType(), DaoStatusConverter.convertJanusGraphStatusToStorageStatus(addPropertiesToArtifactType.right().value())));
336         }
337     }
338
339     /**
340      * Creates an edge between the given TOSCA artifact types and it`s model
341      * @param artifactType the TOSCA artifact types
342      */
343     private void addModelRelation(final ArtifactTypeDefinition artifactType) {
344         final String model = artifactType.getModel();
345         if (StringUtils.isNotEmpty(model)) {
346             final GraphNode from = new UniqueIdData(NodeTypeEnum.Model, UniqueIdBuilder.buildModelUid(model));
347             final GraphNode to = new UniqueIdData(NodeTypeEnum.ArtifactType, artifactType.getUniqueId());
348             LOGGER.info("Connecting model {} to type {}", from, to);
349             final Either<GraphRelation, JanusGraphOperationStatus> status = janusGraphGenericDao.createRelation(from,
350                 to, GraphEdgeLabels.MODEL_ELEMENT, Collections.emptyMap());
351             if (status.isRight()) {
352                 throw new OperationException(ActionStatus.GENERAL_ERROR,
353                     String.format("Failed creating relation between model %s and artifact type %s with status %s",
354                         model, artifactType.getType(), DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status.right().value())));
355             }
356         }
357     }
358
359     /**
360      * Finds a model associated to the given artifact type unique id
361      * @param uid the TOSCA artifact types unique id
362      * @return
363      */
364     private Optional<String> getModelAssociatedToArtifact(final String uid) {
365         final Either<ImmutablePair<ModelData, GraphEdge>, JanusGraphOperationStatus> model =
366             janusGraphGenericDao.getParentNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Interface), uid,
367                 GraphEdgeLabels.MODEL_ELEMENT, NodeTypeEnum.Model, ModelData.class);
368         if (model.isLeft()) {
369             return Optional.ofNullable(model.left().value().getLeft().getName());
370         }
371         return Optional.empty();
372     }
373
374     /**
375      * Finds the derived from for teh given TOSCA artifact types
376      * @param artifactType
377      * @return
378      */
379     private ArtifactTypeData fillDerivedFrom(final ArtifactTypeDefinition artifactType) {
380         final Either<ArtifactTypeData, StorageOperationStatus> result = derivedFromOperation
381             .getDerivedFromChild(artifactType.getUniqueId(), NodeTypeEnum.ArtifactType, ArtifactTypeData.class)
382             .right().bind(this::handleDerivedFromNotExist).left()
383             .map(derivedFrom -> setDerivedFrom(artifactType, derivedFrom));
384         if (result.isRight()) {
385             throw new OperationException(ActionStatus.GENERAL_ERROR,
386                 String.format("Failed fetching derivedFrom for artifact type %s with status %s",
387                     artifactType.getType(), result.right().value()));
388         }
389         return result.left().value();
390     }
391
392     private Either<ArtifactTypeData, StorageOperationStatus> fillDerivedFrom(String uniqueId, ArtifactTypeDefinition artifactType) {
393         LOGGER.debug("#fillDerivedFrom - fetching artifact type {} derived node", artifactType.getType());
394         return derivedFromOperation.getDerivedFromChild(uniqueId, NodeTypeEnum.ArtifactType, ArtifactTypeData.class).right()
395                 .bind(this::handleDerivedFromNotExist).left().map(derivedFrom -> setDerivedFrom(artifactType, derivedFrom));
396     }
397
398     private Either<ArtifactTypeData, StorageOperationStatus> handleDerivedFromNotExist(final StorageOperationStatus storageOperationStatus) {
399         if (storageOperationStatus == StorageOperationStatus.NOT_FOUND) {
400             return Either.left(null);
401         }
402         return Either.right(storageOperationStatus);
403     }
404
405     private ArtifactTypeData setDerivedFrom(final ArtifactTypeDefinition artifactType, final ArtifactTypeData derivedFrom) {
406         if (derivedFrom != null) {
407             artifactType.setDerivedFrom(derivedFrom.getArtifactTypeDataDefinition().getType());
408         }
409         return derivedFrom;
410     }
411
412     /**
413      * Finds all properties for the given TOSCA artifact types
414      * @param artifactType the TOSCA artifact types
415      * @param derivedFromNode the TOSCA artifact types derived from
416      */
417     private void fillProperties(final ArtifactTypeDefinition artifactType, final ArtifactTypeData derivedFromNode) {
418         final Either<List<PropertyDefinition>, StorageOperationStatus> result =
419             propertyOperation.findPropertiesOfNode(NodeTypeEnum.ArtifactType, artifactType.getUniqueId()).right()
420                 .bind(this::handleNoProperties).left().bind(propsMap -> fillDerivedFromProperties(artifactType,
421                     derivedFromNode, new ArrayList<>(propsMap.values())));
422         if (result.isRight()) {
423             throw new OperationException(ActionStatus.GENERAL_ERROR,
424                 String.format("Failed fetching properties for artifact type %s with status %s",
425                     artifactType.getType(), result.right().value()));
426         }
427     }
428
429     private Either<List<PropertyDefinition>, StorageOperationStatus> fillProperties(String uniqueId, ArtifactTypeDefinition artifactType,
430                                                                                     ArtifactTypeData derivedFromNode) {
431         LOGGER.debug("#fillProperties - fetching all properties for artifact type {}", artifactType.getType());
432         return propertyOperation.findPropertiesOfNode(NodeTypeEnum.ArtifactType, uniqueId).right().bind(this::handleArtifactTypeHasNoProperties).left()
433                 .bind(propsMap -> fillDerivedFromProperties(artifactType, derivedFromNode, new ArrayList<>(propsMap.values())));
434     }
435
436     private Either<Map<String, PropertyDefinition>, StorageOperationStatus> handleArtifactTypeHasNoProperties(JanusGraphOperationStatus err) {
437         if (err == JanusGraphOperationStatus.NOT_FOUND) {
438             return Either.left(new HashMap<>());
439         }
440         return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(err));
441     }
442
443     private Either<Map<String, PropertyDefinition>, StorageOperationStatus> handleNoProperties(
444         final JanusGraphOperationStatus janusGraphOperationStatus) {
445         if (janusGraphOperationStatus == JanusGraphOperationStatus.NOT_FOUND) {
446             return Either.left(new HashMap<>());
447         }
448         return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(janusGraphOperationStatus));
449     }
450
451     private Either<List<PropertyDefinition>, StorageOperationStatus> fillDerivedFromProperties(final ArtifactTypeDefinition artifactType,
452                                                                                                final ArtifactTypeData derivedFromNode,
453                                                                                                final List<PropertyDefinition> artifactTypeProperties)
454     {
455         if (derivedFromNode == null) {
456             artifactType.setProperties(artifactTypeProperties);
457             return Either.left(artifactTypeProperties);
458         }
459         return propertyOperation
460             .getAllPropertiesRec(derivedFromNode.getUniqueId(), NodeTypeEnum.ArtifactType, ArtifactTypeData.class)
461             .left().map(derivedFromProps -> {
462                 artifactTypeProperties.addAll(derivedFromProps);
463                 return artifactTypeProperties;
464             }).left().map(allProps -> {
465                 artifactType.setProperties(allProps);
466                 return allProps;
467             });
468     }
469
470     /**
471      * The Model field is an optional entry when uploading a resource. If the field is present, it validates if the Model name exists.
472      * @param modelName Model names declared on the resource json representation
473      */
474     public void validateModel(final String modelName) {
475         if (modelOperation.findModelByName(modelName).isEmpty()) {
476             LOGGER.error(EcompLoggerErrorCode.DATA_ERROR,"Could not find model name {}", modelName);
477             throw ModelOperationExceptionSupplier.invalidModel(modelName).get();
478         }
479     }
480 }