ff4dc0aabde14bb59020196f43bd1ec9f5a9e481
[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(
118                 GraphPropertiesDictionary.TYPE.getProperty(),
119                 capabilityTypeDefinition.getDerivedFrom(), CapabilityTypeData.class, capabilityTypeDefinition.getModel());
120             if (derivedFromNode.isRight()) {
121                 log.error(BUSINESS_PROCESS_ERROR, "Failed to find the derived from type for  {}. status is {}", capabilityTypeDefinition.getType(),
122                     derivedFromNode.right().value());
123                 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(derivedFromNode.right().value()));
124             }
125             Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> allPropertiesRes = getAllCapabilityTypePropertiesFromAllDerivedFrom(
126                 derivedFromNode.left().value().getUniqueId());
127             if (allPropertiesRes.isRight() && !allPropertiesRes.right().value().equals(JanusGraphOperationStatus.NOT_FOUND)) {
128                 error = allPropertiesRes.right().value();
129                 log.debug("Couldn't fetch derived from property nodes for capability type {}, error: {}", capabilityTypeDefinition.getType(), error);
130             }
131             if (error == null && !allPropertiesRes.left().value().isEmpty()) {
132                 Map<String, PropertyDefinition> derivedFromProperties = allPropertiesRes.left().value();
133                 capabilityTypeDefinition.getProperties().entrySet().stream()
134                     .filter(e -> derivedFromProperties.containsKey(e.getKey()) && e.getValue().getType() == null)
135                     .forEach(e -> e.getValue().setType(derivedFromProperties.get(e.getKey()).getType()));
136                 List<PropertyDefinition> properties = capabilityTypeDefinition.getProperties().values().stream().collect(Collectors.toList());
137                 Either<List<PropertyDefinition>, JanusGraphOperationStatus> validatePropertiesRes = propertyOperation
138                     .validatePropertiesUniqueness(allPropertiesRes.left().value(), properties);
139                 if (validatePropertiesRes.isRight()) {
140                     error = validatePropertiesRes.right().value();
141                 }
142             }
143         }
144         if (error == null) {
145             return Either.left(capabilityTypeDefinition);
146         }
147         return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(error));
148     }
149
150     /**
151      * Add capability type to graph.
152      * <p>
153      * 1. Add capability type node
154      * <p>
155      * 2. Add edge between the former node to its parent(if exists)
156      * <p>
157      * 3. Add property node and associate it to the node created at #1. (per property & if exists)
158      *
159      * @param capabilityTypeDefinition
160      * @return
161      */
162     private Either<CapabilityTypeData, StorageOperationStatus> addCapabilityTypeToGraph(CapabilityTypeDefinition capabilityTypeDefinition) {
163         log.debug("Got capability type {}", capabilityTypeDefinition);
164         String ctUniqueId = UniqueIdBuilder.buildCapabilityTypeUid(capabilityTypeDefinition.getModel(), capabilityTypeDefinition.getType());
165         CapabilityTypeData capabilityTypeData = buildCapabilityTypeData(capabilityTypeDefinition, ctUniqueId);
166         log.debug("Before adding capability type to graph. capabilityTypeData = {}", capabilityTypeData);
167         Either<CapabilityTypeData, JanusGraphOperationStatus> createCTResult = janusGraphGenericDao
168             .createNode(capabilityTypeData, CapabilityTypeData.class);
169         log.debug("After adding capability type to graph. status is = {}", createCTResult);
170         if (createCTResult.isRight()) {
171             JanusGraphOperationStatus operationStatus = createCTResult.right().value();
172             log.error("Failed to capability type {} to graph. status is {}", capabilityTypeDefinition.getType(), operationStatus);
173             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(operationStatus));
174         }
175         CapabilityTypeData resultCTD = createCTResult.left().value();
176         Map<String, PropertyDefinition> propertiesMap = capabilityTypeDefinition.getProperties();
177         Either<Map<String, PropertyData>, JanusGraphOperationStatus> addPropertiesToCapablityType = propertyOperation
178             .addPropertiesToElementType(resultCTD.getUniqueId(), NodeTypeEnum.CapabilityType, propertiesMap);
179         if (addPropertiesToCapablityType.isRight()) {
180             log.error("Failed add properties {} to capability {}", propertiesMap, capabilityTypeDefinition.getType());
181             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(addPropertiesToCapablityType.right().value()));
182         }
183
184         final Either<GraphRelation, StorageOperationStatus> modelRelationship = addCapabilityTypeToModel(capabilityTypeDefinition);
185         if (modelRelationship.isRight()) {
186             return Either.right(modelRelationship.right().value());
187         }
188
189         return addDerivedFromRelation(capabilityTypeDefinition, ctUniqueId).left().map(updatedDerivedFrom -> createCTResult.left().value());
190     }
191
192     private Either<GraphRelation, StorageOperationStatus> addCapabilityTypeToModel(final CapabilityTypeDefinition capabilityTypeDefinition) {
193         final String model = capabilityTypeDefinition.getModel();
194         if (model == null) {
195             return Either.left(null);
196         }
197         final GraphNode from = new UniqueIdData(NodeTypeEnum.Model, UniqueIdBuilder.buildModelUid(model));
198         final GraphNode to = new UniqueIdData(NodeTypeEnum.CapabilityType, capabilityTypeDefinition.getUniqueId());
199         log.info("Connecting model {} to type {}", from, to);
200         return janusGraphGenericDao.createRelation(from, to, GraphEdgeLabels.MODEL_ELEMENT, Collections.emptyMap()).right()
201             .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
202     }
203
204     private CapabilityTypeData buildCapabilityTypeData(CapabilityTypeDefinition capabilityTypeDefinition, String ctUniqueId) {
205         CapabilityTypeData capabilityTypeData = new CapabilityTypeData(capabilityTypeDefinition);
206         capabilityTypeData.getCapabilityTypeDataDefinition().setUniqueId(ctUniqueId);
207         Long creationDate = capabilityTypeData.getCapabilityTypeDataDefinition().getCreationTime();
208         if (creationDate == null) {
209             creationDate = System.currentTimeMillis();
210         }
211         capabilityTypeData.getCapabilityTypeDataDefinition().setCreationTime(creationDate);
212         capabilityTypeData.getCapabilityTypeDataDefinition().setModificationTime(creationDate);
213         return capabilityTypeData;
214     }
215
216     @Override
217     public Either<CapabilityTypeDefinition, StorageOperationStatus> getCapabilityType(String uniqueId, boolean inTransaction) {
218         Either<CapabilityTypeDefinition, StorageOperationStatus> result = null;
219         try {
220             Either<CapabilityTypeDefinition, JanusGraphOperationStatus> ctResult = this.getCapabilityTypeByUid(uniqueId);
221             if (ctResult.isRight()) {
222                 JanusGraphOperationStatus status = ctResult.right().value();
223                 if (status != JanusGraphOperationStatus.NOT_FOUND) {
224                     log.error("Failed to retrieve information on capability type {}. status is {}", uniqueId, status);
225                 }
226                 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(ctResult.right().value()));
227                 return result;
228             }
229             result = Either.left(ctResult.left().value());
230             return result;
231         } finally {
232             if (!inTransaction) {
233                 log.debug("Going to execute commit on graph.");
234                 janusGraphGenericDao.commit();
235             }
236         }
237     }
238
239     public Either<CapabilityTypeDefinition, JanusGraphOperationStatus> getCapabilityTypeByType(String capabilityType) {
240         // Optimization: In case of Capability Type its unique ID is the same as type
241         return getCapabilityTypeByUid(capabilityType);
242     }
243
244     public Either<CapabilityTypeDefinition, JanusGraphOperationStatus> getCapabilityTypeByType(final String capabilityType, final String model) {
245         final Either<CapabilityTypeData, JanusGraphOperationStatus> capabilityTypesRes = janusGraphGenericDao
246             .getNode(GraphPropertiesDictionary.TYPE.getProperty(), capabilityType, CapabilityTypeData.class, model);
247         if (capabilityTypesRes.isRight()) {
248             final JanusGraphOperationStatus status = capabilityTypesRes.right().value();
249             log.debug("Capability type {} cannot be found in graph. status is {}", capabilityType, status);
250             return Either.right(status);
251         }
252         return getCapabilityTypeDefinition(capabilityTypesRes.left().value());
253     }
254
255     /**
256      * Build Capability type object from graph by unique id
257      *
258      * @param uniqueId
259      * @return
260      */
261     public Either<CapabilityTypeDefinition, JanusGraphOperationStatus> getCapabilityTypeByUid(String uniqueId) {
262         Either<CapabilityTypeData, JanusGraphOperationStatus> capabilityTypesRes = janusGraphGenericDao
263             .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), uniqueId, CapabilityTypeData.class);
264         if (capabilityTypesRes.isRight()) {
265             JanusGraphOperationStatus status = capabilityTypesRes.right().value();
266             log.debug("Capability type {} cannot be found in graph. status is {}", uniqueId, status);
267             return Either.right(status);
268         }
269         return getCapabilityTypeDefinition(capabilityTypesRes.left().value());
270     }
271
272     private Either<CapabilityTypeDefinition, JanusGraphOperationStatus> getCapabilityTypeDefinition(final CapabilityTypeData ctData) {
273         CapabilityTypeDefinition capabilityTypeDefinition = new CapabilityTypeDefinition(ctData.getCapabilityTypeDataDefinition());
274         Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> propertiesStatus = OperationUtils
275             .fillProperties(ctData.getUniqueId(), propertyOperation, NodeTypeEnum.CapabilityType);
276         if (propertiesStatus.isRight() && propertiesStatus.right().value() != JanusGraphOperationStatus.OK) {
277             log.error(BUSINESS_PROCESS_ERROR, "Failed to fetch properties of capability type {}", ctData.getUniqueId());
278             return Either.right(propertiesStatus.right().value());
279         }
280         if (propertiesStatus.isLeft()) {
281             capabilityTypeDefinition.setProperties(propertiesStatus.left().value());
282         }
283         Either<ImmutablePair<CapabilityTypeData, GraphEdge>, JanusGraphOperationStatus> parentNode = janusGraphGenericDao
284             .getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), ctData.getUniqueId(), GraphEdgeLabels.DERIVED_FROM,
285                 NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
286         log.debug("After retrieving DERIVED_FROM node of {}. status is {}", ctData.getUniqueId(), parentNode);
287         if (parentNode.isRight()) {
288             JanusGraphOperationStatus janusGraphOperationStatus = parentNode.right().value();
289             if (janusGraphOperationStatus != JanusGraphOperationStatus.NOT_FOUND) {
290                 log.error(BUSINESS_PROCESS_ERROR, "Failed to find the parent capability of capability type {}. status is {}", ctData.getUniqueId(),
291                     janusGraphOperationStatus);
292                 return Either.right(janusGraphOperationStatus);
293             }
294         } else {
295             // derived from node was found
296             ImmutablePair<CapabilityTypeData, GraphEdge> immutablePair = parentNode.left().value();
297             CapabilityTypeData parentCT = immutablePair.getKey();
298             capabilityTypeDefinition.setDerivedFrom(parentCT.getCapabilityTypeDataDefinition().getType());
299         }
300
301         final Either<ImmutablePair<ModelData, GraphEdge>, JanusGraphOperationStatus> model = janusGraphGenericDao.getParentNode(
302             UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), ctData.getUniqueId(), GraphEdgeLabels.MODEL_ELEMENT,
303             NodeTypeEnum.Model, ModelData.class);
304         if (model.isLeft()) {
305             capabilityTypeDefinition.setModel(model.left().value().getLeft().getName());
306         }
307
308         return Either.left(capabilityTypeDefinition);
309     }
310
311     public Either<Boolean, StorageOperationStatus> isCapabilityTypeDerivedFrom(String childCandidateType, String parentCandidateType) {
312         return derivedFromOperation
313             .isTypeDerivedFrom(childCandidateType, parentCandidateType, null, NodeTypeEnum.CapabilityType, CapabilityTypeData.class,
314                 t -> t.getCapabilityTypeDataDefinition().getType());
315     }
316
317     @Override
318     public Either<CapabilityTypeDefinition, StorageOperationStatus> updateCapabilityType(CapabilityTypeDefinition capabilityTypeDefNew,
319                                                                                          CapabilityTypeDefinition capabilityTypeDefOld) {
320         log.debug("updating capability type {}", capabilityTypeDefNew.getType());
321         updateCapabilityTypeData(capabilityTypeDefNew, capabilityTypeDefOld);
322         return updateCapabilityTypeOnGraph(capabilityTypeDefNew, capabilityTypeDefOld);
323     }
324
325     private Either<CapabilityTypeDefinition, StorageOperationStatus> updateCapabilityTypeOnGraph(CapabilityTypeDefinition capabilityTypeDefinitionNew,
326                                                                                                  CapabilityTypeDefinition capabilityTypeDefinitionOld) {
327         return janusGraphGenericDao.updateNode(new CapabilityTypeData(capabilityTypeDefinitionNew), CapabilityTypeData.class).right()
328             .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus).left()
329             .bind(updatedNode -> updateProperties(capabilityTypeDefinitionNew.getUniqueId(), capabilityTypeDefinitionNew.getProperties())).left()
330             .bind(updatedProperties -> updateDerivedFrom(capabilityTypeDefinitionNew, capabilityTypeDefinitionOld.getDerivedFrom())).right()
331             .bind(result -> TypeOperations.mapOkStatus(result, null)).left().map(updatedDerivedFrom -> capabilityTypeDefinitionNew);
332     }
333
334     private Either<Map<String, PropertyData>, StorageOperationStatus> updateProperties(String capabilityTypeId,
335                                                                                        Map<String, PropertyDefinition> properties) {
336         log.debug("#updateCapabilityTypeProperties - updating properties for capability type with id {}", capabilityTypeId);
337         return propertyOperation.mergePropertiesAssociatedToNode(NodeTypeEnum.CapabilityType, capabilityTypeId, properties).right()
338             .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
339     }
340
341     private Either<GraphRelation, StorageOperationStatus> updateDerivedFrom(CapabilityTypeDefinition updatedCapabilityType,
342                                                                             String currDerivedFromCapabilityType) {
343         if (StringUtils.equals(updatedCapabilityType.getDerivedFrom(), currDerivedFromCapabilityType)) {
344             return Either.right(StorageOperationStatus.OK);
345         }
346         StorageOperationStatus status = isLegalToReplaceParent(currDerivedFromCapabilityType, updatedCapabilityType.getDerivedFrom(),
347             updatedCapabilityType.getType());
348         if (status != StorageOperationStatus.OK) {
349             return Either.right(status);
350         }
351         String capabilityTypeId = updatedCapabilityType.getUniqueId();
352         log.debug(
353             "#updateCapabilityTypeDerivedFrom - updating capability type derived from relation for capability type with id {}. old derived type {}. new derived type {}",
354             capabilityTypeId, currDerivedFromCapabilityType, updatedCapabilityType.getDerivedFrom());
355         StorageOperationStatus deleteDerivedRelationStatus = deleteDerivedFromCapabilityType(capabilityTypeId, currDerivedFromCapabilityType);
356         if (deleteDerivedRelationStatus != StorageOperationStatus.OK) {
357             return Either.right(deleteDerivedRelationStatus);
358         }
359         return addDerivedFromRelation(updatedCapabilityType, capabilityTypeId);
360     }
361
362     private StorageOperationStatus isLegalToReplaceParent(String oldTypeParent, String newTypeParent, String childType) {
363         return derivedFromOperation
364             .isUpdateParentAllowed(oldTypeParent, newTypeParent, childType, NodeTypeEnum.CapabilityType, CapabilityTypeData.class,
365                 t -> t.getCapabilityTypeDataDefinition().getType());
366     }
367
368     private Either<GraphRelation, StorageOperationStatus> addDerivedFromRelation(CapabilityTypeDefinition capabilityTypeDef, String ptUniqueId) {
369         String derivedFrom = capabilityTypeDef.getDerivedFrom();
370         if (derivedFrom == null) {
371             return Either.left(null);
372         }
373         log.debug("#addDerivedFromRelationBefore - adding derived from relation between capability type {} to its parent {}",
374             capabilityTypeDef.getType(), derivedFrom);
375         return this.getCapabilityTypeByType(derivedFrom, capabilityTypeDef.getModel())
376             .right().map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus)
377             .left().bind(derivedFromCapabilityType -> derivedFromOperation
378                 .addDerivedFromRelation(ptUniqueId, derivedFromCapabilityType.getUniqueId(), NodeTypeEnum.CapabilityType));
379     }
380
381     private StorageOperationStatus deleteDerivedFromCapabilityType(String capabilityTypeId, String derivedFromType) {
382         if (derivedFromType == null) {
383             return StorageOperationStatus.OK;
384         }
385         log.debug("#deleteDerivedFromCapabilityType - deleting derivedFrom relation for capability type with id {} and its derived type {}",
386             capabilityTypeId, derivedFromType);
387         return getCapabilityType(derivedFromType, true).either(derivedFromNode -> derivedFromOperation
388             .removeDerivedFromRelation(capabilityTypeId, derivedFromNode.getUniqueId(), NodeTypeEnum.CapabilityType), err -> err);
389     }
390
391     private void updateCapabilityTypeData(CapabilityTypeDefinition updatedTypeDefinition, CapabilityTypeDefinition currTypeDefinition) {
392         updatedTypeDefinition.setUniqueId(currTypeDefinition.getUniqueId());
393         updatedTypeDefinition.setCreationTime(currTypeDefinition.getCreationTime());
394     }
395
396     /**
397      * FOR TEST ONLY
398      *
399      * @param propertyOperation
400      */
401     public void setPropertyOperation(PropertyOperation propertyOperation) {
402         this.propertyOperation = propertyOperation;
403     }
404
405     @Override
406     public Either<CapabilityTypeDefinition, StorageOperationStatus> addCapabilityType(CapabilityTypeDefinition capabilityTypeDefinition) {
407         return addCapabilityType(capabilityTypeDefinition, true);
408     }
409
410     @Override
411     public Either<CapabilityTypeDefinition, StorageOperationStatus> getCapabilityType(String uniqueId) {
412         return getCapabilityType(uniqueId, true);
413     }
414
415     public Either<Map<String, CapabilityTypeDefinition>, JanusGraphOperationStatus> getAllCapabilityTypes(String modelName) {
416         Map<String, CapabilityTypeDefinition> capabilityTypes = new HashMap<>();
417         Either<Map<String, CapabilityTypeDefinition>, JanusGraphOperationStatus> result = Either.left(capabilityTypes);
418         Either<List<CapabilityTypeData>, JanusGraphOperationStatus> getAllCapabilityTypes = janusGraphGenericDao
419             .getByCriteriaForModel(NodeTypeEnum.CapabilityType, null, modelName, CapabilityTypeData.class);
420         if (getAllCapabilityTypes.isRight()) {
421             JanusGraphOperationStatus status = getAllCapabilityTypes.right().value();
422             if (status != JanusGraphOperationStatus.NOT_FOUND) {
423                 return Either.right(status);
424             } else {
425                 return result;
426             }
427         }
428         List<CapabilityTypeData> list = getAllCapabilityTypes.left().value();
429         if (list != null) {
430             log.trace("Number of data types to load is {}", list.size());
431             //Set properties
432             for (CapabilityTypeData capabilityTypeData : list) {
433                 log.trace("Going to fetch data type {}. uid is {}", capabilityTypeData.getCapabilityTypeDataDefinition().getType(),
434                     capabilityTypeData.getUniqueId());
435                 Either<CapabilityTypeDefinition, JanusGraphOperationStatus> capabilityTypesByUid = getAndAddPropertiesANdDerivedFrom(
436                     capabilityTypeData.getUniqueId(), capabilityTypes);
437                 if (capabilityTypesByUid.isRight()) {
438                     JanusGraphOperationStatus status = capabilityTypesByUid.right().value();
439                     if (status == JanusGraphOperationStatus.NOT_FOUND) {
440                         status = JanusGraphOperationStatus.INVALID_ID;
441                     }
442                     return Either.right(status);
443                 }
444             }
445         }
446         return result;
447     }
448
449     private void fillDerivedFrom(String uniqueId, CapabilityTypeDefinition capabilityType) {
450         log.debug("#fillDerivedFrom - fetching capability type {} derived node", capabilityType.getType());
451         derivedFromOperation.getDerivedFromChild(uniqueId, NodeTypeEnum.CapabilityType, CapabilityTypeData.class).right()
452             .bind(this::handleDerivedFromNotExist).left().map(derivedFrom -> setDerivedFrom(capabilityType, derivedFrom));
453     }
454
455     private Either<CapabilityTypeData, StorageOperationStatus> handleDerivedFromNotExist(StorageOperationStatus err) {
456         if (err == StorageOperationStatus.NOT_FOUND) {
457             return Either.left(null);
458         }
459         return Either.right(err);
460     }
461
462     private CapabilityTypeData setDerivedFrom(CapabilityTypeDefinition capabilityTypeDefinition, CapabilityTypeData derivedFrom) {
463         if (derivedFrom != null) {
464             capabilityTypeDefinition.setDerivedFrom(derivedFrom.getCapabilityTypeDataDefinition().getType());
465         }
466         return derivedFrom;
467     }
468
469     private Either<CapabilityTypeDefinition, JanusGraphOperationStatus> getAndAddPropertiesANdDerivedFrom(String uniqueId,
470                                                                                                           Map<String, CapabilityTypeDefinition> capabilityTypeDefinitionMap) {
471         if (capabilityTypeDefinitionMap.containsKey(uniqueId)) {
472             return Either.left(capabilityTypeDefinitionMap.get(uniqueId));
473         }
474         Either<CapabilityTypeData, JanusGraphOperationStatus> capabilityTypesRes = janusGraphGenericDao
475             .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), uniqueId, CapabilityTypeData.class);
476         if (capabilityTypesRes.isRight()) {
477             JanusGraphOperationStatus status = capabilityTypesRes.right().value();
478             log.debug(DATA_TYPE_CANNOT_BE_FOUND_IN_GRAPH_STATUS_IS, uniqueId, status);
479             return Either.right(status);
480         }
481         CapabilityTypeData ctData = capabilityTypesRes.left().value();
482         CapabilityTypeDefinition capabilityTypeDefinition = new CapabilityTypeDefinition(ctData.getCapabilityTypeDataDefinition());
483         Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> propertiesStatus = OperationUtils
484             .fillProperties(uniqueId, propertyOperation, NodeTypeEnum.CapabilityType);
485         if (propertiesStatus.isRight() && propertiesStatus.right().value() != JanusGraphOperationStatus.OK) {
486             log.error(FAILED_TO_FETCH_PROPERTIES_OF_DATA_TYPE, uniqueId);
487             return Either.right(propertiesStatus.right().value());
488         }
489         if (propertiesStatus.isLeft()) {
490             capabilityTypeDefinition.setProperties(propertiesStatus.left().value());
491         }
492         fillDerivedFrom(uniqueId, capabilityTypeDefinition);
493         capabilityTypeDefinitionMap.put(capabilityTypeDefinition.getType(), capabilityTypeDefinition);
494         return Either.left(capabilityTypeDefinition);
495     }
496 }