Consider component model when retrieving capability types
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / operations / impl / CapabilityTypeOperation.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.openecomp.sdc.be.model.operations.impl;
21
22 import static org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR;
23
24 import fj.data.Either;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.stream.Collectors;
30 import org.apache.commons.collections.MapUtils;
31 import org.apache.commons.lang3.StringUtils;
32 import org.apache.commons.lang3.tuple.ImmutablePair;
33 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
34 import org.openecomp.sdc.be.dao.graph.datatype.GraphNode;
35 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
36 import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphGenericDao;
37 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
38 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
39 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
40 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
41 import org.openecomp.sdc.be.model.CapabilityTypeDefinition;
42 import org.openecomp.sdc.be.model.PropertyDefinition;
43 import org.openecomp.sdc.be.model.operations.api.DerivedFromOperation;
44 import org.openecomp.sdc.be.model.operations.api.ICapabilityTypeOperation;
45 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
46 import org.openecomp.sdc.be.model.operations.api.TypeOperations;
47 import org.openecomp.sdc.be.resources.data.CapabilityTypeData;
48 import org.openecomp.sdc.be.resources.data.ModelData;
49 import org.openecomp.sdc.be.resources.data.PropertyData;
50 import org.openecomp.sdc.be.resources.data.UniqueIdData;
51 import org.openecomp.sdc.common.log.wrappers.Logger;
52 import org.springframework.beans.factory.annotation.Autowired;
53 import org.springframework.stereotype.Component;
54
55 @Component("capability-type-operation")
56 public class CapabilityTypeOperation extends AbstractOperation implements ICapabilityTypeOperation {
57
58     private static final Logger log = Logger.getLogger(CapabilityTypeOperation.class.getName());
59     private static final String DATA_TYPE_CANNOT_BE_FOUND_IN_GRAPH_STATUS_IS = "Data type {} cannot be found in graph." + " status is {}";
60     private static final String FAILED_TO_FETCH_PROPERTIES_OF_DATA_TYPE = "Failed to fetch properties of data type {}";
61     @Autowired
62     private PropertyOperation propertyOperation;
63     @Autowired
64     private DerivedFromOperation derivedFromOperation;
65
66     public CapabilityTypeOperation() {
67         super();
68     }
69
70     /**
71      * FOR TEST ONLY
72      *
73      * @param janusGraphGenericDao
74      */
75     public void setJanusGraphGenericDao(HealingJanusGraphGenericDao janusGraphGenericDao) {
76         this.janusGraphGenericDao = janusGraphGenericDao;
77     }
78
79     @Override
80     public Either<CapabilityTypeDefinition, StorageOperationStatus> addCapabilityType(CapabilityTypeDefinition capabilityTypeDefinition,
81                                                                                       boolean inTransaction) {
82         Either<CapabilityTypeDefinition, StorageOperationStatus> result = null;
83         try {
84             Either<CapabilityTypeDefinition, StorageOperationStatus> validationRes = validateUpdateProperties(capabilityTypeDefinition);
85             if (validationRes.isRight()) {
86                 log.error("#addCapabilityType - One or all properties of capability type {} not valid. status is {}", capabilityTypeDefinition,
87                     validationRes.right().value());
88                 return result;
89             }
90             Either<CapabilityTypeData, StorageOperationStatus> eitherStatus = addCapabilityTypeToGraph(capabilityTypeDefinition);
91             result = eitherStatus.left().map(CapabilityTypeData::getUniqueId).left().bind(uniqueId -> getCapabilityType(uniqueId, inTransaction));
92             if (result.isLeft()) {
93                 log.debug("#addCapabilityType - The returned CapabilityTypeDefinition is {}", result.left().value());
94             }
95             return result;
96         } finally {
97             if (!inTransaction) {
98                 if (result == null || result.isRight()) {
99                     log.error("#addCapabilityType - Going to execute rollback on graph.");
100                     janusGraphGenericDao.rollback();
101                 } else {
102                     log.debug("#addCapabilityType - Going to execute commit on graph.");
103                     janusGraphGenericDao.commit();
104                 }
105             }
106         }
107     }
108
109     public Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> getAllCapabilityTypePropertiesFromAllDerivedFrom(
110         final String firstParentUid) {
111         return propertyOperation.getAllTypePropertiesFromAllDerivedFrom(firstParentUid, NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
112     }
113
114     public Either<CapabilityTypeDefinition, StorageOperationStatus> validateUpdateProperties(CapabilityTypeDefinition capabilityTypeDefinition) {
115         JanusGraphOperationStatus error = null;
116         if (MapUtils.isNotEmpty(capabilityTypeDefinition.getProperties()) && capabilityTypeDefinition.getDerivedFrom() != null) {
117             final Either<CapabilityTypeData, JanusGraphOperationStatus> derivedFromNode = janusGraphGenericDao.getNode(GraphPropertiesDictionary.TYPE.getProperty(), 
118                 capabilityTypeDefinition.getDerivedFrom(), CapabilityTypeData.class, capabilityTypeDefinition.getModel());
119             if (derivedFromNode.isRight()) {
120                 log.error(BUSINESS_PROCESS_ERROR, "Failed to find the derived from type for  {}. status is {}", capabilityTypeDefinition.getType(), derivedFromNode.right().value());
121                 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(derivedFromNode.right().value()));
122             }
123             Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> allPropertiesRes = getAllCapabilityTypePropertiesFromAllDerivedFrom(
124                 derivedFromNode.left().value().getUniqueId());
125             if (allPropertiesRes.isRight() && !allPropertiesRes.right().value().equals(JanusGraphOperationStatus.NOT_FOUND)) {
126                 error = allPropertiesRes.right().value();
127                 log.debug("Couldn't fetch derived from property nodes for capability type {}, error: {}", capabilityTypeDefinition.getType(), error);
128             }
129             if (error == null && !allPropertiesRes.left().value().isEmpty()) {
130                 Map<String, PropertyDefinition> derivedFromProperties = allPropertiesRes.left().value();
131                 capabilityTypeDefinition.getProperties().entrySet().stream()
132                     .filter(e -> derivedFromProperties.containsKey(e.getKey()) && e.getValue().getType() == null)
133                     .forEach(e -> e.getValue().setType(derivedFromProperties.get(e.getKey()).getType()));
134                 List<PropertyDefinition> properties = capabilityTypeDefinition.getProperties().values().stream().collect(Collectors.toList());
135                 Either<List<PropertyDefinition>, JanusGraphOperationStatus> validatePropertiesRes = propertyOperation
136                     .validatePropertiesUniqueness(allPropertiesRes.left().value(), properties);
137                 if (validatePropertiesRes.isRight()) {
138                     error = validatePropertiesRes.right().value();
139                 }
140             }
141         }
142         if (error == null) {
143             return Either.left(capabilityTypeDefinition);
144         }
145         return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(error));
146     }
147
148     /**
149      * Add capability type to graph.
150      * <p>
151      * 1. Add capability type node
152      * <p>
153      * 2. Add edge between the former node to its parent(if exists)
154      * <p>
155      * 3. Add property node and associate it to the node created at #1. (per property & if exists)
156      *
157      * @param capabilityTypeDefinition
158      * @return
159      */
160     private Either<CapabilityTypeData, StorageOperationStatus> addCapabilityTypeToGraph(CapabilityTypeDefinition capabilityTypeDefinition) {
161         log.debug("Got capability type {}", capabilityTypeDefinition);
162         String ctUniqueId = UniqueIdBuilder.buildCapabilityTypeUid(capabilityTypeDefinition.getModel(), capabilityTypeDefinition.getType());
163         CapabilityTypeData capabilityTypeData = buildCapabilityTypeData(capabilityTypeDefinition, ctUniqueId);
164         log.debug("Before adding capability type to graph. capabilityTypeData = {}", capabilityTypeData);
165         Either<CapabilityTypeData, JanusGraphOperationStatus> createCTResult = janusGraphGenericDao
166             .createNode(capabilityTypeData, CapabilityTypeData.class);
167         log.debug("After adding capability type to graph. status is = {}", createCTResult);
168         if (createCTResult.isRight()) {
169             JanusGraphOperationStatus operationStatus = createCTResult.right().value();
170             log.error("Failed to capability type {} to graph. status is {}", capabilityTypeDefinition.getType(), operationStatus);
171             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(operationStatus));
172         }
173         CapabilityTypeData resultCTD = createCTResult.left().value();
174         Map<String, PropertyDefinition> propertiesMap = capabilityTypeDefinition.getProperties();
175         Either<Map<String, PropertyData>, JanusGraphOperationStatus> addPropertiesToCapablityType = propertyOperation
176             .addPropertiesToElementType(resultCTD.getUniqueId(), NodeTypeEnum.CapabilityType, propertiesMap);
177         if (addPropertiesToCapablityType.isRight()) {
178             log.error("Failed add properties {} to capability {}", propertiesMap, capabilityTypeDefinition.getType());
179             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(addPropertiesToCapablityType.right().value()));
180         }
181         
182         final Either<GraphRelation, StorageOperationStatus> modelRelationship = addCapabilityTypeToModel(capabilityTypeDefinition);
183         if (modelRelationship.isRight()) {
184             return Either.right(modelRelationship.right().value());
185         } 
186         
187         return addDerivedFromRelation(capabilityTypeDefinition, ctUniqueId).left().map(updatedDerivedFrom -> createCTResult.left().value());
188     }
189     
190     private Either<GraphRelation, StorageOperationStatus> addCapabilityTypeToModel(final CapabilityTypeDefinition capabilityTypeDefinition) {
191         final String model = capabilityTypeDefinition.getModel();
192         if (model == null) {
193             return Either.left(null);
194         }
195         final GraphNode from = new UniqueIdData(NodeTypeEnum.Model, UniqueIdBuilder.buildModelUid(model));
196         final GraphNode to = new UniqueIdData(NodeTypeEnum.CapabilityType, capabilityTypeDefinition.getUniqueId());
197         log.info("Connecting model {} to type {}", from, to);
198         return janusGraphGenericDao.createRelation(from , to, GraphEdgeLabels.MODEL_ELEMENT, Collections.emptyMap()).right().map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
199     }
200
201     private CapabilityTypeData buildCapabilityTypeData(CapabilityTypeDefinition capabilityTypeDefinition, String ctUniqueId) {
202         CapabilityTypeData capabilityTypeData = new CapabilityTypeData(capabilityTypeDefinition);
203         capabilityTypeData.getCapabilityTypeDataDefinition().setUniqueId(ctUniqueId);
204         Long creationDate = capabilityTypeData.getCapabilityTypeDataDefinition().getCreationTime();
205         if (creationDate == null) {
206             creationDate = System.currentTimeMillis();
207         }
208         capabilityTypeData.getCapabilityTypeDataDefinition().setCreationTime(creationDate);
209         capabilityTypeData.getCapabilityTypeDataDefinition().setModificationTime(creationDate);
210         return capabilityTypeData;
211     }
212
213     @Override
214     public Either<CapabilityTypeDefinition, StorageOperationStatus> getCapabilityType(String uniqueId, boolean inTransaction) {
215         Either<CapabilityTypeDefinition, StorageOperationStatus> result = null;
216         try {
217             Either<CapabilityTypeDefinition, JanusGraphOperationStatus> ctResult = this.getCapabilityTypeByUid(uniqueId);
218             if (ctResult.isRight()) {
219                 JanusGraphOperationStatus status = ctResult.right().value();
220                 if (status != JanusGraphOperationStatus.NOT_FOUND) {
221                     log.error("Failed to retrieve information on capability type {}. status is {}", uniqueId, status);
222                 }
223                 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(ctResult.right().value()));
224                 return result;
225             }
226             result = Either.left(ctResult.left().value());
227             return result;
228         } finally {
229             if (!inTransaction) {
230                 log.debug("Going to execute commit on graph.");
231                 janusGraphGenericDao.commit();
232             }
233         }
234     }
235
236     public Either<CapabilityTypeDefinition, JanusGraphOperationStatus> getCapabilityTypeByType(String capabilityType) {
237         // Optimization: In case of Capability Type its unique ID is the same as type
238         return getCapabilityTypeByUid(capabilityType);
239     }
240     
241     public Either<CapabilityTypeDefinition, JanusGraphOperationStatus> getCapabilityTypeByType(final String capabilityType, final String model) {
242         final Either<CapabilityTypeData, JanusGraphOperationStatus> capabilityTypesRes = janusGraphGenericDao
243             .getNode(GraphPropertiesDictionary.TYPE.getProperty(), capabilityType, CapabilityTypeData.class, model);
244         if (capabilityTypesRes.isRight()) {
245             final JanusGraphOperationStatus status = capabilityTypesRes.right().value();
246             log.debug("Capability type {} cannot be found in graph. status is {}", capabilityType, status);
247             return Either.right(status);
248         }
249         return getCapabilityTypeDefinition(capabilityTypesRes.left().value());
250     }
251
252     /**
253      * Build Capability type object from graph by unique id
254      *
255      * @param uniqueId
256      * @return
257      */
258     public Either<CapabilityTypeDefinition, JanusGraphOperationStatus> getCapabilityTypeByUid(String uniqueId) {
259         Either<CapabilityTypeDefinition, JanusGraphOperationStatus> result = null;
260         Either<CapabilityTypeData, JanusGraphOperationStatus> capabilityTypesRes = janusGraphGenericDao
261             .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), uniqueId, CapabilityTypeData.class);
262         if (capabilityTypesRes.isRight()) {
263             JanusGraphOperationStatus status = capabilityTypesRes.right().value();
264             log.debug("Capability type {} cannot be found in graph. status is {}", uniqueId, status);
265             return Either.right(status);
266         }
267         return getCapabilityTypeDefinition(capabilityTypesRes.left().value());
268     }
269     
270     private Either<CapabilityTypeDefinition, JanusGraphOperationStatus> getCapabilityTypeDefinition(final CapabilityTypeData ctData) {
271         CapabilityTypeDefinition capabilityTypeDefinition = new CapabilityTypeDefinition(ctData.getCapabilityTypeDataDefinition());
272         Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> propertiesStatus = OperationUtils
273             .fillProperties(ctData.getUniqueId(), propertyOperation, NodeTypeEnum.CapabilityType);
274         if (propertiesStatus.isRight() && propertiesStatus.right().value() != JanusGraphOperationStatus.OK) {
275             log.error(BUSINESS_PROCESS_ERROR, "Failed to fetch properties of capability type {}", ctData.getUniqueId());
276             return Either.right(propertiesStatus.right().value());
277         }
278         if (propertiesStatus.isLeft()) {
279             capabilityTypeDefinition.setProperties(propertiesStatus.left().value());
280         }
281         Either<ImmutablePair<CapabilityTypeData, GraphEdge>, JanusGraphOperationStatus> parentNode = janusGraphGenericDao
282             .getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), ctData.getUniqueId(), GraphEdgeLabels.DERIVED_FROM,
283                 NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
284         log.debug("After retrieving DERIVED_FROM node of {}. status is {}", ctData.getUniqueId(), parentNode);
285         if (parentNode.isRight()) {
286             JanusGraphOperationStatus janusGraphOperationStatus = parentNode.right().value();
287             if (janusGraphOperationStatus != JanusGraphOperationStatus.NOT_FOUND) {
288                 log.error(BUSINESS_PROCESS_ERROR, "Failed to find the parent capability of capability type {}. status is {}", ctData.getUniqueId(), janusGraphOperationStatus);
289                 return Either.right(janusGraphOperationStatus);
290             }
291         } else {
292             // derived from node was found
293             ImmutablePair<CapabilityTypeData, GraphEdge> immutablePair = parentNode.left().value();
294             CapabilityTypeData parentCT = immutablePair.getKey();
295             capabilityTypeDefinition.setDerivedFrom(parentCT.getCapabilityTypeDataDefinition().getType());
296         }
297         
298         final Either<ImmutablePair<ModelData, GraphEdge>, JanusGraphOperationStatus> model = janusGraphGenericDao.getParentNode(
299             UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), ctData.getUniqueId(), GraphEdgeLabels.MODEL_ELEMENT, 
300             NodeTypeEnum.Model, ModelData.class);
301         if (model.isLeft()) {
302             capabilityTypeDefinition.setModel(model.left().value().getLeft().getName());
303         }
304         
305         return Either.left(capabilityTypeDefinition);
306     }
307
308     public Either<Boolean, StorageOperationStatus> isCapabilityTypeDerivedFrom(String childCandidateType, String parentCandidateType) {
309         return derivedFromOperation
310             .isTypeDerivedFrom(childCandidateType, parentCandidateType, null, NodeTypeEnum.CapabilityType, CapabilityTypeData.class,
311                 t -> t.getCapabilityTypeDataDefinition().getType());
312     }
313
314     @Override
315     public Either<CapabilityTypeDefinition, StorageOperationStatus> updateCapabilityType(CapabilityTypeDefinition capabilityTypeDefNew,
316                                                                                          CapabilityTypeDefinition capabilityTypeDefOld) {
317         log.debug("updating capability type {}", capabilityTypeDefNew.getType());
318         updateCapabilityTypeData(capabilityTypeDefNew, capabilityTypeDefOld);
319         return updateCapabilityTypeOnGraph(capabilityTypeDefNew, capabilityTypeDefOld);
320     }
321
322     private Either<CapabilityTypeDefinition, StorageOperationStatus> updateCapabilityTypeOnGraph(CapabilityTypeDefinition capabilityTypeDefinitionNew,
323                                                                                                  CapabilityTypeDefinition capabilityTypeDefinitionOld) {
324         return janusGraphGenericDao.updateNode(new CapabilityTypeData(capabilityTypeDefinitionNew), CapabilityTypeData.class).right()
325             .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus).left()
326             .bind(updatedNode -> updateProperties(capabilityTypeDefinitionNew.getUniqueId(), capabilityTypeDefinitionNew.getProperties())).left()
327             .bind(updatedProperties -> updateDerivedFrom(capabilityTypeDefinitionNew, capabilityTypeDefinitionOld.getDerivedFrom())).right()
328             .bind(result -> TypeOperations.mapOkStatus(result, null)).left().map(updatedDerivedFrom -> capabilityTypeDefinitionNew);
329     }
330
331     private Either<Map<String, PropertyData>, StorageOperationStatus> updateProperties(String capabilityTypeId,
332                                                                                        Map<String, PropertyDefinition> properties) {
333         log.debug("#updateCapabilityTypeProperties - updating properties for capability type with id {}", capabilityTypeId);
334         return propertyOperation.mergePropertiesAssociatedToNode(NodeTypeEnum.CapabilityType, capabilityTypeId, properties).right()
335             .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
336     }
337
338     private Either<GraphRelation, StorageOperationStatus> updateDerivedFrom(CapabilityTypeDefinition updatedCapabilityType,
339                                                                             String currDerivedFromCapabilityType) {
340         if (StringUtils.equals(updatedCapabilityType.getDerivedFrom(), currDerivedFromCapabilityType)) {
341             return Either.right(StorageOperationStatus.OK);
342         }
343         StorageOperationStatus status = isLegalToReplaceParent(currDerivedFromCapabilityType, updatedCapabilityType.getDerivedFrom(),
344             updatedCapabilityType.getType());
345         if (status != StorageOperationStatus.OK) {
346             return Either.right(status);
347         }
348         String capabilityTypeId = updatedCapabilityType.getUniqueId();
349         log.debug(
350             "#updateCapabilityTypeDerivedFrom - updating capability type derived from relation for capability type with id {}. old derived type {}. new derived type {}",
351             capabilityTypeId, currDerivedFromCapabilityType, updatedCapabilityType.getDerivedFrom());
352         StorageOperationStatus deleteDerivedRelationStatus = deleteDerivedFromCapabilityType(capabilityTypeId, currDerivedFromCapabilityType);
353         if (deleteDerivedRelationStatus != StorageOperationStatus.OK) {
354             return Either.right(deleteDerivedRelationStatus);
355         }
356         return addDerivedFromRelation(updatedCapabilityType, capabilityTypeId);
357     }
358
359     private StorageOperationStatus isLegalToReplaceParent(String oldTypeParent, String newTypeParent, String childType) {
360         return derivedFromOperation
361             .isUpdateParentAllowed(oldTypeParent, newTypeParent, childType, NodeTypeEnum.CapabilityType, CapabilityTypeData.class,
362                 t -> t.getCapabilityTypeDataDefinition().getType());
363     }
364
365     private Either<GraphRelation, StorageOperationStatus> addDerivedFromRelation(CapabilityTypeDefinition capabilityTypeDef, String ptUniqueId) {
366         String derivedFrom = capabilityTypeDef.getDerivedFrom();
367         if (derivedFrom == null) {
368             return Either.left(null);
369         }
370         log.debug("#addDerivedFromRelationBefore - adding derived from relation between capability type {} to its parent {}",
371             capabilityTypeDef.getType(), derivedFrom);
372         return this.getCapabilityTypeByType(derivedFrom, capabilityTypeDef.getModel())
373             .right().map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus)
374             .left().bind(derivedFromCapabilityType -> derivedFromOperation
375                 .addDerivedFromRelation(ptUniqueId, derivedFromCapabilityType.getUniqueId(), NodeTypeEnum.CapabilityType));
376     }
377
378     private StorageOperationStatus deleteDerivedFromCapabilityType(String capabilityTypeId, String derivedFromType) {
379         if (derivedFromType == null) {
380             return StorageOperationStatus.OK;
381         }
382         log.debug("#deleteDerivedFromCapabilityType - deleting derivedFrom relation for capability type with id {} and its derived type {}",
383             capabilityTypeId, derivedFromType);
384         return getCapabilityType(derivedFromType, true).either(derivedFromNode -> derivedFromOperation
385             .removeDerivedFromRelation(capabilityTypeId, derivedFromNode.getUniqueId(), NodeTypeEnum.CapabilityType), err -> err);
386     }
387
388     private void updateCapabilityTypeData(CapabilityTypeDefinition updatedTypeDefinition, CapabilityTypeDefinition currTypeDefinition) {
389         updatedTypeDefinition.setUniqueId(currTypeDefinition.getUniqueId());
390         updatedTypeDefinition.setCreationTime(currTypeDefinition.getCreationTime());
391     }
392
393     /**
394      * FOR TEST ONLY
395      *
396      * @param propertyOperation
397      */
398     public void setPropertyOperation(PropertyOperation propertyOperation) {
399         this.propertyOperation = propertyOperation;
400     }
401
402     @Override
403     public Either<CapabilityTypeDefinition, StorageOperationStatus> addCapabilityType(CapabilityTypeDefinition capabilityTypeDefinition) {
404         return addCapabilityType(capabilityTypeDefinition, true);
405     }
406
407     @Override
408     public Either<CapabilityTypeDefinition, StorageOperationStatus> getCapabilityType(String uniqueId) {
409         return getCapabilityType(uniqueId, true);
410     }
411
412     public Either<Map<String, CapabilityTypeDefinition>, JanusGraphOperationStatus> getAllCapabilityTypes(String modelName) {
413         Map<String, CapabilityTypeDefinition> capabilityTypes = new HashMap<>();
414         Either<Map<String, CapabilityTypeDefinition>, JanusGraphOperationStatus> result = Either.left(capabilityTypes);
415         Either<List<CapabilityTypeData>, JanusGraphOperationStatus> getAllCapabilityTypes = janusGraphGenericDao
416             .getByCriteriaForModel(NodeTypeEnum.CapabilityType, null, modelName, CapabilityTypeData.class);
417         if (getAllCapabilityTypes.isRight()) {
418             JanusGraphOperationStatus status = getAllCapabilityTypes.right().value();
419             if (status != JanusGraphOperationStatus.NOT_FOUND) {
420                 return Either.right(status);
421             } else {
422                 return result;
423             }
424         }
425         List<CapabilityTypeData> list = getAllCapabilityTypes.left().value();
426         if (list != null) {
427             log.trace("Number of data types to load is {}", list.size());
428             //Set properties
429             for (CapabilityTypeData capabilityTypeData : list) {
430                 log.trace("Going to fetch data type {}. uid is {}", capabilityTypeData.getCapabilityTypeDataDefinition().getType(),
431                     capabilityTypeData.getUniqueId());
432                 Either<CapabilityTypeDefinition, JanusGraphOperationStatus> capabilityTypesByUid = getAndAddPropertiesANdDerivedFrom(
433                     capabilityTypeData.getUniqueId(), capabilityTypes);
434                 if (capabilityTypesByUid.isRight()) {
435                     JanusGraphOperationStatus status = capabilityTypesByUid.right().value();
436                     if (status == JanusGraphOperationStatus.NOT_FOUND) {
437                         status = JanusGraphOperationStatus.INVALID_ID;
438                     }
439                     return Either.right(status);
440                 }
441             }
442         }
443         return result;
444     }
445
446     private void fillDerivedFrom(String uniqueId, CapabilityTypeDefinition capabilityType) {
447         log.debug("#fillDerivedFrom - fetching capability type {} derived node", capabilityType.getType());
448         derivedFromOperation.getDerivedFromChild(uniqueId, NodeTypeEnum.CapabilityType, CapabilityTypeData.class).right()
449             .bind(this::handleDerivedFromNotExist).left().map(derivedFrom -> setDerivedFrom(capabilityType, derivedFrom));
450     }
451
452     private Either<CapabilityTypeData, StorageOperationStatus> handleDerivedFromNotExist(StorageOperationStatus err) {
453         if (err == StorageOperationStatus.NOT_FOUND) {
454             return Either.left(null);
455         }
456         return Either.right(err);
457     }
458
459     private CapabilityTypeData setDerivedFrom(CapabilityTypeDefinition capabilityTypeDefinition, CapabilityTypeData derivedFrom) {
460         if (derivedFrom != null) {
461             capabilityTypeDefinition.setDerivedFrom(derivedFrom.getCapabilityTypeDataDefinition().getType());
462         }
463         return derivedFrom;
464     }
465
466     private Either<CapabilityTypeDefinition, JanusGraphOperationStatus> getAndAddPropertiesANdDerivedFrom(String uniqueId,
467                                                                                                           Map<String, CapabilityTypeDefinition> capabilityTypeDefinitionMap) {
468         if (capabilityTypeDefinitionMap.containsKey(uniqueId)) {
469             return Either.left(capabilityTypeDefinitionMap.get(uniqueId));
470         }
471         Either<CapabilityTypeData, JanusGraphOperationStatus> capabilityTypesRes = janusGraphGenericDao
472             .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), uniqueId, CapabilityTypeData.class);
473         if (capabilityTypesRes.isRight()) {
474             JanusGraphOperationStatus status = capabilityTypesRes.right().value();
475             log.debug(DATA_TYPE_CANNOT_BE_FOUND_IN_GRAPH_STATUS_IS, uniqueId, status);
476             return Either.right(status);
477         }
478         CapabilityTypeData ctData = capabilityTypesRes.left().value();
479         CapabilityTypeDefinition capabilityTypeDefinition = new CapabilityTypeDefinition(ctData.getCapabilityTypeDataDefinition());
480         Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> propertiesStatus = OperationUtils
481             .fillProperties(uniqueId, propertyOperation, NodeTypeEnum.CapabilityType);
482         if (propertiesStatus.isRight() && propertiesStatus.right().value() != JanusGraphOperationStatus.OK) {
483             log.error(FAILED_TO_FETCH_PROPERTIES_OF_DATA_TYPE, uniqueId);
484             return Either.right(propertiesStatus.right().value());
485         }
486         if (propertiesStatus.isLeft()) {
487             capabilityTypeDefinition.setProperties(propertiesStatus.left().value());
488         }
489         fillDerivedFrom(uniqueId, capabilityTypeDefinition);
490         capabilityTypeDefinitionMap.put(capabilityTypeDefinition.getType(), capabilityTypeDefinition);
491         return Either.left(capabilityTypeDefinition);
492     }
493 }