Implement 'Update Service by importing Tosca Model'-story
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / jsonjanusgraph / operations / ToscaElementLifecycleOperation.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.jsonjanusgraph.operations;
21
22 import static fj.P.p;
23
24 import fj.P2;
25 import fj.data.Either;
26 import java.util.ArrayList;
27 import java.util.EnumMap;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Optional;
33 import java.util.stream.Collectors;
34 import org.apache.commons.collections.CollectionUtils;
35 import org.apache.commons.collections.MapUtils;
36 import org.apache.commons.lang3.StringUtils;
37 import org.apache.commons.lang3.tuple.ImmutablePair;
38 import org.apache.tinkerpop.gremlin.structure.Direction;
39 import org.apache.tinkerpop.gremlin.structure.Edge;
40 import org.apache.tinkerpop.gremlin.structure.Vertex;
41 import org.janusgraph.core.JanusGraphVertex;
42 import org.openecomp.sdc.be.config.ConfigurationManager;
43 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
44 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
45 import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
46 import org.openecomp.sdc.be.dao.jsongraph.types.EdgePropertyEnum;
47 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
48 import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
49 import org.openecomp.sdc.be.dao.jsongraph.utils.IdBuilderUtils;
50 import org.openecomp.sdc.be.dao.jsongraph.utils.JsonParserUtils;
51 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
52 import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition;
53 import org.openecomp.sdc.be.datatypes.elements.CompositionDataDefinition;
54 import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition;
55 import org.openecomp.sdc.be.datatypes.elements.GroupInstanceDataDefinition;
56 import org.openecomp.sdc.be.datatypes.elements.MapArtifactDataDefinition;
57 import org.openecomp.sdc.be.datatypes.elements.MapGroupsDataDefinition;
58 import org.openecomp.sdc.be.datatypes.elements.MapPropertiesDataDefinition;
59 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
60 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
61 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
62 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
63 import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum;
64 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
65 import org.openecomp.sdc.be.model.DistributionStatusEnum;
66 import org.openecomp.sdc.be.model.LifecycleStateEnum;
67 import org.openecomp.sdc.be.model.Model;
68 import org.openecomp.sdc.be.model.User;
69 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.TopologyTemplate;
70 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement;
71 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElementTypeEnum;
72 import org.openecomp.sdc.be.model.jsonjanusgraph.enums.JsonConstantKeysEnum;
73 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
74 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
75 import org.openecomp.sdc.be.model.operations.impl.ModelOperation;
76 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
77 import org.openecomp.sdc.common.jsongraph.util.CommonUtility;
78 import org.openecomp.sdc.common.jsongraph.util.CommonUtility.LogLevelEnum;
79 import org.openecomp.sdc.common.log.wrappers.Logger;
80 import org.springframework.beans.factory.annotation.Autowired;
81
82 @org.springframework.stereotype.Component("tosca-element-lifecycle-operation")
83 /**
84  * Allows to perform lifecycle operations: checkin, checkout, submit for testing, start certification and certification process for tosca element
85  */
86 public class ToscaElementLifecycleOperation extends BaseOperation {
87
88     public static final String VERSION_DELIMITER = ".";
89     public static final String VERSION_DELIMITER_REGEXP = "\\.";
90     private static final String FAILED_TO_GET_VERTICES = "Failed to get vertices by id {}. Status is {}. ";
91     private static final Logger log = Logger.getLogger(ToscaElementLifecycleOperation.class);
92     private final ModelOperation modelOperation;
93
94     @Autowired
95     public ToscaElementLifecycleOperation(ModelOperation modelOperation) {
96         this.modelOperation = modelOperation;
97     }
98
99     static StorageOperationStatus handleFailureToPrepareParameters(final JanusGraphOperationStatus status, final String toscaElementId) {
100         CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId);
101         return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status);
102     }
103
104     static Either<ToscaElement, StorageOperationStatus> getToscaElementFromOperation(final ToscaElementOperation operation, final String uniqueId,
105                                                                                      final String toscaElementId) {
106         return operation.getToscaElement(uniqueId).right().map(status -> {
107             //We log a potential error we got while retrieving the ToscaElement
108             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to get updated tosca element {}. Status is {}", toscaElementId, status);
109             return status;
110         });
111     }
112
113     private static StorageOperationStatus logDebugMessageAndReturnStorageOperationStatus(final StorageOperationStatus status, final String msg,
114                                                                                          final Object... args) {
115         CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, msg, args);
116         return status;
117     }
118
119     /**
120      * Performs changing a lifecycle state of tosca element from "checked out" or "ready for certification" to "checked in"
121      *
122      * @param currState
123      * @param toscaElementId
124      * @param modifierId
125      * @param ownerId
126      * @return
127      */
128     public Either<ToscaElement, StorageOperationStatus> checkinToscaELement(LifecycleStateEnum currState, String toscaElementId, String modifierId,
129                                                                             String ownerId) {
130         try {
131             return janusGraphDao.getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForCheckin(toscaElementId, modifierId, ownerId))
132                 .right().map(status -> handleFailureToPrepareParameters(status, toscaElementId)).left().bind(
133                     verticesMap -> checkinToscaELement(verticesMap.get(toscaElementId), verticesMap.get(ownerId),
134                         verticesMap.get(modifierId), LifecycleStateEnum.NOT_CERTIFIED_CHECKIN).left().bind(checkinResult -> {
135                         //We retrieve the operation
136                         ToscaElementOperation operation = getToscaElementOperation(verticesMap.get(toscaElementId).getLabel());
137                         //We retrieve the ToscaElement from the operation
138                         return getToscaElementFromOperation(operation, checkinResult.getUniqueId(), toscaElementId);
139                     }));
140         } catch (Exception e) {
141             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Exception occurred during checkin of tosca element {}. {} ", toscaElementId,
142                 e.getMessage());
143             return Either.right(StorageOperationStatus.GENERAL_ERROR);
144         }
145     }
146
147     /**
148      * Returns vertex presenting owner of tosca element specified by uniqueId
149      *
150      * @param toscaElementId
151      * @return
152      */
153     public Either<User, StorageOperationStatus> getToscaElementOwner(String toscaElementId) {
154         Either<User, StorageOperationStatus> result = null;
155         GraphVertex toscaElement = null;
156         Either<GraphVertex, JanusGraphOperationStatus> getToscaElementRes = janusGraphDao.getVertexById(toscaElementId, JsonParseFlagEnum.NoParse);
157         if (getToscaElementRes.isRight()) {
158             result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(getToscaElementRes.right().value()));
159         }
160         if (result == null) {
161             toscaElement = getToscaElementRes.left().value();
162             Iterator<Vertex> vertices = toscaElement.getVertex().vertices(Direction.IN, EdgeLabelEnum.STATE.name());
163             if (vertices == null || !vertices.hasNext()) {
164                 result = Either.right(StorageOperationStatus.NOT_FOUND);
165             } else {
166                 result = Either.left(convertToUser(vertices.next()));
167             }
168         }
169         return result;
170     }
171
172     /**
173      * Returns vertex presenting owner of tosca element specified by uniqueId
174      *
175      * @param toscaElement
176      * @return
177      */
178     public Either<User, StorageOperationStatus> getToscaElementOwner(GraphVertex toscaElement) {
179         Iterator<Vertex> vertices = toscaElement.getVertex().vertices(Direction.IN, EdgeLabelEnum.STATE.name());
180         if (vertices == null || !vertices.hasNext()) {
181             return Either.right(StorageOperationStatus.NOT_FOUND);
182         } else {
183             return Either.left(convertToUser(vertices.next()));
184         }
185     }
186
187     /**
188      * Performs checkout of a tosca element
189      *
190      * @param toscaElementId
191      * @param modifierId
192      * @param ownerId
193      * @return
194      */
195     public Either<ToscaElement, StorageOperationStatus> checkoutToscaElement(String toscaElementId, String modifierId, String ownerId) {
196         Either<ToscaElement, StorageOperationStatus> result = null;
197         Map<String, GraphVertex> vertices = null;
198         try {
199             Either<Map<String, GraphVertex>, JanusGraphOperationStatus> getVerticesRes = janusGraphDao
200                 .getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForCheckout(toscaElementId, modifierId, ownerId));
201             if (getVerticesRes.isRight()) {
202                 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId);
203                 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(getVerticesRes.right().value()));
204             }
205             if (result == null) {
206                 vertices = getVerticesRes.left().value();
207                 // update previous component if not certified
208                 StorageOperationStatus status = updatePreviousVersion(vertices.get(toscaElementId), vertices.get(ownerId));
209                 if (status != StorageOperationStatus.OK) {
210                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update vertex with id {} . Status is {}. ", status);
211                     result = Either.right(status);
212                 }
213             }
214             if (result == null) {
215                 result = cloneToscaElementForCheckout(vertices.get(toscaElementId), vertices.get(modifierId));
216                 if (result.isRight()) {
217                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to checkout tosca element {}. Status is {} ", toscaElementId,
218                         result.right().value());
219                 }
220             }
221         } catch (Exception e) {
222             CommonUtility
223                 .addRecordToLog(log, LogLevelEnum.DEBUG, "Exception occured during checkout tosca element {}. {}", toscaElementId, e.getMessage());
224         }
225         return result;
226     }
227
228     /**
229      * Performs undo checkout for tosca element
230      *
231      * @param toscaElementId
232      * @return
233      */
234     public Either<ToscaElement, StorageOperationStatus> undoCheckout(String toscaElementId, String model) {
235         try {
236             return janusGraphDao.getVertexById(toscaElementId, JsonParseFlagEnum.ParseMetadata).right().map(errorStatus -> {
237                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId);
238                     return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(errorStatus);
239                 }).left().bind(this::retrieveAndUpdatePreviousVersion).left()
240                 .bind(tuple -> updateEdgeToCatalogRootAndReturnPreVersionElement(tuple, model));
241         } catch (Exception e) {
242             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Exception occurred during undo checkout tosca element {}. {}", toscaElementId,
243                 e.getMessage());
244             return null;
245         }
246     }
247
248     private Either<P2<GraphVertex, JanusGraphVertex>, StorageOperationStatus> retrieveAndUpdatePreviousVersion(final GraphVertex currVersionV) {
249         if (!hasPreviousVersion(currVersionV)) {
250             return Either.left(p(currVersionV, null));
251         } else {
252             // find previous version
253             Iterator<Edge> nextVersionComponentIter = currVersionV.getVertex().edges(Direction.IN, EdgeLabelEnum.VERSION.name());
254             if (nextVersionComponentIter == null || !nextVersionComponentIter.hasNext()) {
255                 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to fetch previous version of tosca element with name {}. ",
256                     currVersionV.getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME).toString());
257                 return Either.right(StorageOperationStatus.NOT_FOUND);
258             } else {
259                 Vertex preVersionVertex = nextVersionComponentIter.next().outVertex();
260                 StorageOperationStatus updateOldResourceResult = updateOldToscaElementBeforeUndoCheckout(preVersionVertex);
261                 if (updateOldResourceResult != StorageOperationStatus.OK) {
262                     return Either.right(updateOldResourceResult);
263                 } else {
264                     P2<GraphVertex, JanusGraphVertex> result = p(currVersionV, (JanusGraphVertex) preVersionVertex);
265                     return Either.left(result);
266                 }
267             }
268         }
269     }
270
271     private Either<ToscaElement, StorageOperationStatus> updateEdgeToCatalogRootAndReturnPreVersionElement(
272         final P2<GraphVertex, JanusGraphVertex> tuple, final String model) {
273         final GraphVertex currVersionV = tuple._1();
274         final JanusGraphVertex preVersionVertex = tuple._2();
275         StorageOperationStatus updateCatalogRes = updateEdgeToCatalogRootByUndoCheckout(preVersionVertex, currVersionV);
276         if (updateCatalogRes != StorageOperationStatus.OK) {
277             return Either.right(updateCatalogRes);
278         } else {
279             final Optional<Model> modelOptional = modelOperation.findModelByName(model);
280             if (modelOptional.isPresent() && modelOptional.get().getModelType() == ModelTypeEnum.NORMATIVE_EXTENSION) {
281                 modelOperation.deleteModel(modelOptional.get(), false);
282             }
283             final ToscaElementOperation operation = getToscaElementOperation(currVersionV.getLabel());
284             return operation.deleteToscaElement(currVersionV).left().bind(discarded -> getUpdatedPreVersionElement(operation, preVersionVertex));
285         }
286     }
287
288     private Either<ToscaElement, StorageOperationStatus> getUpdatedPreVersionElement(final ToscaElementOperation operation,
289                                                                                      final JanusGraphVertex preVersionVertex) {
290         if (preVersionVertex == null) {
291             return Either.left(null);
292         } else {
293             String uniqueIdPreVer = (String) janusGraphDao.getProperty(preVersionVertex, GraphPropertyEnum.UNIQUE_ID.getProperty());
294             return operation.getToscaElement(uniqueIdPreVer);
295         }
296     }
297
298     private boolean hasPreviousVersion(GraphVertex toscaElementVertex) {
299         boolean hasPreviousVersion = true;
300         String version = (String) toscaElementVertex.getMetadataProperty(GraphPropertyEnum.VERSION);
301         if (StringUtils.isEmpty(version) || "0.1".equals(version)) {
302             hasPreviousVersion = false;
303         }
304         return hasPreviousVersion;
305     }
306
307     public Either<ToscaElement, StorageOperationStatus> certifyToscaElement(String toscaElementId, String modifierId, String ownerId) {
308         try {
309             return janusGraphDao
310                 .getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForRequestCertification(toscaElementId, modifierId, ownerId)).right()
311                 .map(status -> logDebugMessageAndReturnStorageOperationStatus(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status),
312                     FAILED_TO_GET_VERTICES, toscaElementId)).left().bind(verticesRes -> {
313                     GraphVertex toscaElement = verticesRes.get(toscaElementId);
314                     GraphVertex modifier = verticesRes.get(modifierId);
315                     Integer majorVersion = getMajorVersion((String) toscaElement.getMetadataProperty(GraphPropertyEnum.VERSION));
316                     return handleRelationsBeforeCertifyingAndProcessClone(toscaElement, modifier, majorVersion);
317                 });
318         } catch (Exception e) {
319             return Either.right(logDebugMessageAndReturnStorageOperationStatus(StorageOperationStatus.GENERAL_ERROR,
320                 "Exception occurred during certification tosca element {}.", toscaElementId, e));
321         }
322     }
323
324     private Either<ToscaElement, StorageOperationStatus> handleRelationsBeforeCertifyingAndProcessClone(GraphVertex toscaElement,
325                                                                                                         GraphVertex modifier, Integer majorVersion) {
326         StorageOperationStatus status = handleRelationsOfPreviousToscaElementBeforeCertifying(toscaElement, majorVersion);
327         if (status != StorageOperationStatus.OK) {
328             return Either.right(logDebugMessageAndReturnStorageOperationStatus(status,
329                 "Failed to handle relations of previous tosca element before certifying {}. Status is {}. ", toscaElement.getUniqueId(), status));
330         } else {
331             return cloneToscaElementAndHandleRelations(toscaElement, modifier, majorVersion);
332         }
333     }
334
335     private Either<ToscaElement, StorageOperationStatus> cloneToscaElementAndHandleRelations(GraphVertex toscaElement, GraphVertex modifier,
336                                                                                              Integer majorVersion) {
337         return cloneToscaElementForCertify(toscaElement, modifier, majorVersion).right()
338             .map(status -> logDebugMessageAndReturnStorageOperationStatus(status, "Failed to clone tosca element during certification. ")).left()
339             .bind(certifiedToscaElement -> handleRelationsOfNewestCertifiedToscaElementAndReturn(toscaElement, certifiedToscaElement));
340     }
341
342     private Either<ToscaElement, StorageOperationStatus> handleRelationsOfNewestCertifiedToscaElementAndReturn(GraphVertex toscaElement,
343                                                                                                                GraphVertex certifiedToscaElement) {
344         StorageOperationStatus status = handleRelationsOfNewestCertifiedToscaElement(toscaElement, certifiedToscaElement);
345         if (status != StorageOperationStatus.OK) {
346             return Either.right(logDebugMessageAndReturnStorageOperationStatus(status,
347                 "Failed to handle relations of newest certified tosca element {}. Status is {}. ", certifiedToscaElement.getUniqueId(), status));
348         } else {
349             return getToscaElementOperation(toscaElement.getLabel()).getToscaElement(certifiedToscaElement.getUniqueId());
350         }
351     }
352
353     private StorageOperationStatus handleRelationsOfNewestCertifiedToscaElement(GraphVertex toscaElement, GraphVertex certifiedToscaElement) {
354         JanusGraphOperationStatus createVersionEdgeStatus = janusGraphDao
355             .createEdge(toscaElement, certifiedToscaElement, EdgeLabelEnum.VERSION, new HashMap<>());
356         if (createVersionEdgeStatus != JanusGraphOperationStatus.OK) {
357             CommonUtility
358                 .addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to create version edge from last element {} to new certified element {}. status=",
359                     toscaElement.getUniqueId(), certifiedToscaElement.getUniqueId(), createVersionEdgeStatus);
360             return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(createVersionEdgeStatus);
361         }
362         return StorageOperationStatus.OK;
363     }
364
365     public Either<GraphVertex, JanusGraphOperationStatus> findUser(String userId) {
366         return findUserVertex(userId);
367     }
368
369     private Either<Boolean, StorageOperationStatus> markToscaElementsAsDeleted(ToscaElementOperation operation, List<GraphVertex> toscaElements) {
370         Either<Boolean, StorageOperationStatus> result = Either.left(true);
371         for (GraphVertex resourceToDelete : toscaElements) {
372             if (!(resourceToDelete.getJsonMetadataField(JsonPresentationFields.LIFECYCLE_STATE)).equals(LifecycleStateEnum.CERTIFIED.name())) {
373                 Either<GraphVertex, StorageOperationStatus> deleteElementRes = operation.markComponentToDelete(resourceToDelete);
374                 if (deleteElementRes.isRight()) {
375                     CommonUtility
376                         .addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to delete tosca element {}. Status is {}. ", resourceToDelete.getUniqueId(),
377                             deleteElementRes.right().value());
378                     result = Either.right(deleteElementRes.right().value());
379                     break;
380                 }
381             }
382         }
383         return result;
384     }
385
386     private StorageOperationStatus handleRelationsOfPreviousToscaElementBeforeCertifying(GraphVertex toscaElement,
387                                                                                          Integer majorVersion) {
388         StorageOperationStatus result = null;
389         if (majorVersion > 0) {
390             Either<Vertex, StorageOperationStatus> findRes = findLastCertifiedToscaElementVertex(toscaElement);
391             if (findRes.isRight()) {
392                 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to fetch last certified tosca element {} . Status is {}. ",
393                     toscaElement.getMetadataProperty(GraphPropertyEnum.NAME), findRes.right().value());
394                 result = findRes.right().value();
395             }
396             if (result == null) {
397                 Vertex lastCertifiedVertex = findRes.left().value();
398                 Map<GraphPropertyEnum, Object> properties = new EnumMap<>(GraphPropertyEnum.class);
399                 properties.put(GraphPropertyEnum.IS_HIGHEST_VERSION, false);
400                 JanusGraphOperationStatus status = janusGraphDao.updateVertexMetadataPropertiesWithJson(lastCertifiedVertex, properties);
401                 if (status != JanusGraphOperationStatus.OK) {
402                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to set highest version  of tosca element {} to [{}]. Status is {}",
403                         toscaElement.getUniqueId(), false, status);
404                     result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status);
405                 }
406                 // remove previous certified version from the catalog
407                 GraphVertex lastCertifiedV = new GraphVertex();
408                 lastCertifiedV.setVertex((JanusGraphVertex) lastCertifiedVertex);
409                 lastCertifiedV.setUniqueId(
410                     (String) janusGraphDao.getProperty((JanusGraphVertex) lastCertifiedVertex, GraphPropertyEnum.UNIQUE_ID.getProperty()));
411                 lastCertifiedV.addMetadataProperty(GraphPropertyEnum.IS_ABSTRACT,
412                     (Boolean) janusGraphDao.getProperty((JanusGraphVertex) lastCertifiedVertex, GraphPropertyEnum.IS_ABSTRACT.getProperty()));
413                 StorageOperationStatus res = updateEdgeToCatalogRoot(null, lastCertifiedV);
414                 if (res != StorageOperationStatus.OK) {
415                     return res;
416                 }
417             }
418         }
419         if (result == null) {
420             result = StorageOperationStatus.OK;
421         }
422         return result;
423     }
424
425     private Either<Vertex, StorageOperationStatus> findLastCertifiedToscaElementVertex(GraphVertex toscaElement) {
426         return findLastCertifiedToscaElementVertexRecursively(toscaElement.getVertex());
427     }
428
429     private Either<Vertex, StorageOperationStatus> findLastCertifiedToscaElementVertexRecursively(Vertex vertex) {
430         if (isCertifiedVersion((String) vertex.property(GraphPropertyEnum.VERSION.getProperty()).value())) {
431             return Either.left(vertex);
432         }
433         Iterator<Edge> edgeIter = vertex.edges(Direction.IN, EdgeLabelEnum.VERSION.name());
434         if (!edgeIter.hasNext()) {
435             return Either.right(StorageOperationStatus.NOT_FOUND);
436         }
437         return findLastCertifiedToscaElementVertexRecursively(edgeIter.next().outVertex());
438     }
439
440     private boolean isCertifiedVersion(String version) {
441         String[] versionParts = version.split(VERSION_DELIMITER_REGEXP);
442         return Integer.parseInt(versionParts[0]) > 0 && Integer.parseInt(versionParts[1]) == 0;
443     }
444
445     private StorageOperationStatus updateOldToscaElementBeforeUndoCheckout(Vertex previousVersionToscaElement) {
446         StorageOperationStatus result = StorageOperationStatus.OK;
447         String previousVersion = (String) previousVersionToscaElement.property(GraphPropertyEnum.VERSION.getProperty()).value();
448         if (!previousVersion.endsWith(".0")) {
449             try {
450                 CommonUtility.addRecordToLog(log, LogLevelEnum.TRACE, "Going to update vertex of previous version of tosca element",
451                     previousVersionToscaElement.property(GraphPropertyEnum.NORMALIZED_NAME.getProperty()));
452                 Map<String, Object> propertiesToUpdate = new HashMap<>();
453                 propertiesToUpdate.put(GraphPropertyEnum.IS_HIGHEST_VERSION.getProperty(), true);
454                 Map<String, Object> jsonMetadataMap = JsonParserUtils
455                     .toMap((String) previousVersionToscaElement.property(GraphPropertyEnum.METADATA.getProperty()).value());
456                 jsonMetadataMap.put(GraphPropertyEnum.IS_HIGHEST_VERSION.getProperty(), true);
457                 propertiesToUpdate.put(GraphPropertyEnum.METADATA.getProperty(), JsonParserUtils.toJson(jsonMetadataMap));
458                 janusGraphDao.setVertexProperties(previousVersionToscaElement, propertiesToUpdate);
459                 Iterator<Edge> edgesIter = previousVersionToscaElement.edges(Direction.IN, EdgeLabelEnum.LAST_STATE.name());
460                 if (!edgesIter.hasNext()) {
461                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to fetch last modifier vertex for tosca element {}. ",
462                         previousVersionToscaElement.property(GraphPropertyEnum.NORMALIZED_NAME.getProperty()));
463                     result = StorageOperationStatus.NOT_FOUND;
464                 } else {
465                     Edge lastStateEdge = edgesIter.next();
466                     Vertex lastModifier = lastStateEdge.outVertex();
467                     JanusGraphOperationStatus replaceRes = janusGraphDao
468                         .replaceEdgeLabel(lastModifier, previousVersionToscaElement, lastStateEdge, EdgeLabelEnum.LAST_STATE, EdgeLabelEnum.STATE);
469                     if (replaceRes != JanusGraphOperationStatus.OK) {
470                         CommonUtility
471                             .addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to replace label from {} to {}. status = {}", EdgeLabelEnum.LAST_STATE,
472                                 EdgeLabelEnum.STATE, replaceRes);
473                         result = StorageOperationStatus.INCONSISTENCY;
474                         if (replaceRes != JanusGraphOperationStatus.INVALID_ID) {
475                             result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(replaceRes);
476                         }
477                     }
478                 }
479             } catch (Exception e) {
480                 CommonUtility
481                     .addRecordToLog(log, LogLevelEnum.DEBUG, "Exception occured during update previous tosca element {} before undo checkout. {} ",
482                         e.getMessage());
483             }
484         }
485         return result;
486     }
487
488     private StorageOperationStatus updatePreviousVersion(GraphVertex toscaElementVertex, GraphVertex ownerVertex) {
489         StorageOperationStatus result = null;
490         String ownerId = (String) ownerVertex.getMetadataProperty(GraphPropertyEnum.USERID);
491         String toscaElementId = toscaElementVertex.getUniqueId();
492         if (!toscaElementVertex.getMetadataProperty(GraphPropertyEnum.STATE).equals(LifecycleStateEnum.CERTIFIED.name())) {
493             toscaElementVertex.addMetadataProperty(GraphPropertyEnum.IS_HIGHEST_VERSION, false);
494             Either<GraphVertex, JanusGraphOperationStatus> updateVertexRes = janusGraphDao.updateVertex(toscaElementVertex);
495             if (updateVertexRes.isRight()) {
496                 JanusGraphOperationStatus titatStatus = updateVertexRes.right().value();
497                 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update tosca element vertex {}. Status is  {}",
498                     toscaElementVertex.getUniqueId(), titatStatus);
499                 result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(titatStatus);
500             }
501             Either<Edge, JanusGraphOperationStatus> deleteEdgeRes = null;
502             if (result == null) {
503                 CommonUtility
504                     .addRecordToLog(log, LogLevelEnum.TRACE, "Going to replace edge with label {} to label {} from {} to {}. ", EdgeLabelEnum.STATE,
505                         EdgeLabelEnum.LAST_STATE, ownerId, toscaElementId);
506                 deleteEdgeRes = janusGraphDao.deleteEdge(ownerVertex, toscaElementVertex, EdgeLabelEnum.STATE);
507                 if (deleteEdgeRes.isRight()) {
508                     JanusGraphOperationStatus janusGraphStatus = deleteEdgeRes.right().value();
509                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to delete edge with label {} from {} to {}. Status is {} ",
510                         EdgeLabelEnum.STATE, EdgeLabelEnum.LAST_STATE, ownerId, toscaElementId, janusGraphStatus);
511                     if (!janusGraphStatus.equals(JanusGraphOperationStatus.INVALID_ID)) {
512                         result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(janusGraphStatus);
513                     } else {
514                         result = StorageOperationStatus.INCONSISTENCY;
515                     }
516                 }
517             }
518             if (result == null) {
519                 JanusGraphOperationStatus createEdgeRes = janusGraphDao
520                     .createEdge(ownerVertex.getVertex(), toscaElementVertex.getVertex(), EdgeLabelEnum.LAST_STATE, deleteEdgeRes.left().value());
521                 if (createEdgeRes != JanusGraphOperationStatus.OK) {
522                     result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(createEdgeRes);
523                 }
524             }
525         }
526         if (result == null) {
527             result = StorageOperationStatus.OK;
528         }
529         return result;
530     }
531
532     private Either<ToscaElement, StorageOperationStatus> cloneToscaElementForCheckout(GraphVertex toscaElementVertex, GraphVertex modifierVertex) {
533         Either<ToscaElement, StorageOperationStatus> result = null;
534         Either<GraphVertex, StorageOperationStatus> cloneResult = null;
535         ToscaElementOperation operation = getToscaElementOperation(toscaElementVertex.getLabel());
536         // check if component with the next version doesn't exist.
537         Iterator<Edge> nextVersionComponentIter = toscaElementVertex.getVertex().edges(Direction.OUT, EdgeLabelEnum.VERSION.name());
538         if (nextVersionComponentIter != null && nextVersionComponentIter.hasNext()) {
539             Vertex nextVersionVertex = nextVersionComponentIter.next().inVertex();
540             String fetchedVersion = (String) nextVersionVertex.property(GraphPropertyEnum.VERSION.getProperty()).value();
541             String fetchedName = (String) nextVersionVertex.property(GraphPropertyEnum.NORMALIZED_NAME.getProperty()).value();
542             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG,
543                 "Failed to checkout component {} with version {}. The component with name {} and version {} was fetched from graph as existing following version. ",
544                 toscaElementVertex.getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME).toString(),
545                 toscaElementVertex.getMetadataProperty(GraphPropertyEnum.VERSION).toString(), fetchedName, fetchedVersion);
546             result = Either.right(StorageOperationStatus.ENTITY_ALREADY_EXISTS);
547         }
548         if (result == null) {
549             toscaElementVertex.getOrSetDefaultInstantiationTypeForToscaElementJson();
550             cloneResult = operation
551                 .cloneToscaElement(toscaElementVertex, cloneGraphVertexForCheckout(toscaElementVertex, modifierVertex), modifierVertex);
552             if (cloneResult.isRight()) {
553                 result = Either.right(cloneResult.right().value());
554             }
555         }
556         GraphVertex clonedVertex = null;
557         if (result == null) {
558             clonedVertex = cloneResult.left().value();
559             JanusGraphOperationStatus status = janusGraphDao
560                 .createEdge(toscaElementVertex.getVertex(), cloneResult.left().value().getVertex(), EdgeLabelEnum.VERSION, new HashMap<>());
561             if (status != JanusGraphOperationStatus.OK) {
562                 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG,
563                     "Failed to create edge with label {} from vertex {} to tosca element vertex {} on graph. Status is {}. ", EdgeLabelEnum.VERSION,
564                     toscaElementVertex.getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME),
565                     cloneResult.left().value().getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME), status);
566                 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
567             }
568         }
569         if (result == null) {
570             Boolean isHighest = (Boolean) toscaElementVertex.getMetadataProperty(GraphPropertyEnum.IS_HIGHEST_VERSION);
571             GraphVertex prevVersionInCatalog = (isHighest != null && isHighest) ? null : toscaElementVertex;
572             StorageOperationStatus updateCatalogRes = updateEdgeToCatalogRoot(clonedVertex, prevVersionInCatalog);
573             if (updateCatalogRes != StorageOperationStatus.OK) {
574                 return Either.right(updateCatalogRes);
575             }
576             result = operation.getToscaElement(cloneResult.left().value().getUniqueId());
577             if (result.isRight()) {
578                 return result;
579             }
580             ToscaElement toscaElement = result.left().value();
581             if (toscaElement.getToscaType() == ToscaElementTypeEnum.TOPOLOGY_TEMPLATE) {
582                 result = handleFixTopologyTemplate(toscaElementVertex, result, operation, clonedVertex, toscaElement);
583             }
584         }
585         return result;
586     }
587
588     private Either<ToscaElement, StorageOperationStatus> handleFixTopologyTemplate(GraphVertex toscaElementVertex,
589                                                                                    Either<ToscaElement, StorageOperationStatus> result,
590                                                                                    ToscaElementOperation operation, GraphVertex clonedVertex,
591                                                                                    ToscaElement toscaElement) {
592         TopologyTemplate topologyTemplate = (TopologyTemplate) toscaElement;
593         Map<String, MapPropertiesDataDefinition> instInputs = topologyTemplate.getInstInputs();
594         Map<String, MapGroupsDataDefinition> instGroups = topologyTemplate.getInstGroups();
595         Map<String, MapArtifactDataDefinition> instArtifactsMap = topologyTemplate.getInstanceArtifacts();
596         Map<String, ToscaElement> origCompMap = new HashMap<>();
597         if (instInputs == null) {
598             instInputs = new HashMap<>();
599         }
600         if (instGroups == null) {
601             instGroups = new HashMap<>();
602         }
603         if (instArtifactsMap == null) {
604             instArtifactsMap = new HashMap<>();
605         }
606         Map<String, ComponentInstanceDataDefinition> instancesMap = topologyTemplate.getComponentInstances();
607         boolean isAddInstGroup = instGroups == null || instGroups.isEmpty();
608         boolean needUpdateComposition = false;
609         if (instancesMap != null && !instancesMap.isEmpty()) {
610             for (ComponentInstanceDataDefinition vfInst : instancesMap.values()) {
611                 CommonUtility
612                     .addRecordToLog(log, LogLevelEnum.DEBUG, "vfInst name is {} . OriginType {}. ", vfInst.getName(), vfInst.getOriginType());
613                 if (vfInst.getOriginType().name().equals(OriginTypeEnum.VF.name())) {
614                     collectInstanceInputAndGroups(instInputs, instGroups, instArtifactsMap, origCompMap, isAddInstGroup, vfInst, clonedVertex);
615                 }
616                 needUpdateComposition = needUpdateComposition || fixToscaComponentName(vfInst, origCompMap);
617                 if (needUpdateComposition) {
618                     instancesMap.put(vfInst.getUniqueId(), vfInst);
619                 }
620             }
621             CommonUtility
622                 .addRecordToLog(log, LogLevelEnum.DEBUG, "before add to graph instInputs {}  instGroups {} needUpdateComposition {}", instInputs,
623                     instGroups, needUpdateComposition);
624             if (!instInputs.isEmpty()) {
625                 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "before add inst inputs {} ", instInputs == null ? 0 : instInputs.size());
626                 GraphVertex toscaDataVertex = null;
627                 Either<GraphVertex, JanusGraphOperationStatus> instInpVertexEither = janusGraphDao
628                     .getChildVertex(toscaElementVertex, EdgeLabelEnum.INST_INPUTS, JsonParseFlagEnum.ParseJson);
629                 if (instInpVertexEither.isLeft()) {
630                     toscaDataVertex = instInpVertexEither.left().value();
631                 }
632                 StorageOperationStatus status = handleToscaData(clonedVertex, VertexTypeEnum.INST_INPUTS, EdgeLabelEnum.INST_INPUTS, toscaDataVertex,
633                     instInputs);
634                 if (status != StorageOperationStatus.OK) {
635                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update instance inputs . Status is {}. ", status);
636                     result = Either.right(status);
637                     return result;
638                 }
639             }
640             if (!instGroups.isEmpty()) {
641                 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "before add inst groups {} ", instGroups == null ? 0 : instGroups.size());
642                 GraphVertex toscaDataVertex = null;
643                 Either<GraphVertex, JanusGraphOperationStatus> instGrVertexEither = janusGraphDao
644                     .getChildVertex(toscaElementVertex, EdgeLabelEnum.INST_GROUPS, JsonParseFlagEnum.ParseJson);
645                 if (instGrVertexEither.isLeft()) {
646                     toscaDataVertex = instGrVertexEither.left().value();
647                 }
648                 StorageOperationStatus status = handleToscaData(clonedVertex, VertexTypeEnum.INST_GROUPS, EdgeLabelEnum.INST_GROUPS, toscaDataVertex,
649                     instGroups);
650                 if (status != StorageOperationStatus.OK) {
651                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update instance group . Status is {}. ", status);
652                     result = Either.right(status);
653                     return result;
654                 }
655             }
656             if (needUpdateComposition) {
657                 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "before update Instances ");
658                 Map<String, CompositionDataDefinition> jsonComposition = (Map<String, CompositionDataDefinition>) clonedVertex.getJson();
659                 CompositionDataDefinition compositionDataDefinition = jsonComposition.get(JsonConstantKeysEnum.COMPOSITION.getValue());
660                 compositionDataDefinition.setComponentInstances(instancesMap);
661                 Either<GraphVertex, JanusGraphOperationStatus> updateElement = janusGraphDao.updateVertex(clonedVertex);
662                 if (updateElement.isRight()) {
663                     JanusGraphOperationStatus status = updateElement.right().value();
664                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update instances on metadata vertex . Status is {}. ", status);
665                     result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
666                     return result;
667                 }
668             }
669             result = operation.getToscaElement(clonedVertex.getUniqueId());
670         } else {
671             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "RI map empty on component {}", toscaElement.getUniqueId());
672         }
673         return result;
674     }
675
676     // TODO remove after jsonModelMigration
677     public boolean resolveToscaComponentName(ComponentInstanceDataDefinition vfInst, Map<String, ToscaElement> origCompMap) {
678         return fixToscaComponentName(vfInst, origCompMap);
679     }
680
681     private boolean fixToscaComponentName(ComponentInstanceDataDefinition vfInst, Map<String, ToscaElement> origCompMap) {
682         if (vfInst.getToscaComponentName() == null || vfInst.getToscaComponentName().isEmpty()) {
683             String ciUid = vfInst.getUniqueId();
684             String origCompUid = vfInst.getComponentUid();
685             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "fixToscaComponentName:: Ri id {} . origin component id is {}. type is{} ", ciUid,
686                 origCompUid, vfInst.getOriginType());
687             ToscaElement origComp = null;
688             if (!origCompMap.containsKey(origCompUid)) {
689                 Either<ToscaElement, StorageOperationStatus> origCompEither;
690                 if (vfInst.getOriginType() == null || vfInst.getOriginType().name().equals(OriginTypeEnum.VF.name())) {
691                     origCompEither = topologyTemplateOperation.getToscaElement(origCompUid);
692                 } else {
693                     origCompEither = nodeTypeOperation.getToscaElement(origCompUid);
694                 }
695                 if (origCompEither.isRight()) {
696                     CommonUtility
697                         .addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to find orig component {} . Status is {}. ", origCompEither.right().value());
698                     return false;
699                 }
700                 origComp = origCompEither.left().value();
701                 origCompMap.put(origCompUid, origComp);
702             } else {
703                 origComp = origCompMap.get(origCompUid);
704             }
705             String toscaName = (String) origComp.getMetadataValue(JsonPresentationFields.TOSCA_RESOURCE_NAME);
706             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Origin component id is {}. toscaName {}", origCompUid, toscaName);
707             vfInst.setToscaComponentName(toscaName);
708             return true;
709         }
710         return false;
711     }
712
713     private void collectInstanceInputAndGroups(Map<String, MapPropertiesDataDefinition> instInputs, Map<String, MapGroupsDataDefinition> instGroups,
714                                                Map<String, MapArtifactDataDefinition> instArtifactsMap, Map<String, ToscaElement> origCompMap,
715                                                boolean isAddInstGroup, ComponentInstanceDataDefinition vfInst, GraphVertex clonedVertex) {
716         String ciUid = vfInst.getUniqueId();
717         String origCompUid = vfInst.getComponentUid();
718         CommonUtility
719             .addRecordToLog(log, LogLevelEnum.DEBUG, "collectInstanceInputAndGroups:: Ri id {} . origin component id is {}. ", ciUid, origCompUid);
720         TopologyTemplate origComp = null;
721         if (!origCompMap.containsKey(origCompUid)) {
722             Either<ToscaElement, StorageOperationStatus> origCompEither = topologyTemplateOperation.getToscaElement(origCompUid);
723             if (origCompEither.isRight()) {
724                 CommonUtility
725                     .addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to find orig component {} . Status is {}. ", origCompEither.right().value());
726                 return;
727             }
728             origComp = (TopologyTemplate) origCompEither.left().value();
729             origCompMap.put(origCompUid, origComp);
730         } else {
731             origComp = (TopologyTemplate) origCompMap.get(origCompUid);
732         }
733         CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Orig component {}. ", origComp.getUniqueId());
734         Map<String, PropertyDataDefinition> origInputs = origComp.getInputs();
735         CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Orig component inputs size {}. ", origInputs == null ? 0 : origInputs.size());
736         if (origInputs != null) {
737             if (!instInputs.containsKey(ciUid)) {
738                 MapPropertiesDataDefinition instProperties = new MapPropertiesDataDefinition(origInputs);
739                 instInputs.put(ciUid, instProperties);
740             } else {
741                 MapPropertiesDataDefinition instInputMap = instInputs.get(ciUid);
742                 Map<String, PropertyDataDefinition> instProp = instInputMap.getMapToscaDataDefinition();
743                 origInputs.forEach((propName, propMap) -> {
744                     if (!instProp.containsKey(propName)) {
745                         instProp.put(propName, propMap);
746                     }
747                 });
748             }
749             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "ComponentInstanseInputs {}. ", instInputs.get(ciUid));
750         }
751         if (isAddInstGroup) {
752             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "before create group instance. ");
753             List<GroupDataDefinition> filteredGroups = null;
754             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "check vf groups before filter. Size is {} ",
755                 filteredGroups == null ? 0 : filteredGroups.size());
756             if (origComp.getGroups() != null && !origComp.getGroups().isEmpty()) {
757                 filteredGroups = origComp.getGroups().values().stream().filter(g -> g.getType().equals(VF_MODULE)).collect(Collectors.toList());
758                 CommonUtility
759                     .addRecordToLog(log, LogLevelEnum.DEBUG, "check vf groups . Size is {} ", filteredGroups == null ? 0 : filteredGroups.size());
760             }
761             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "check vf groups after filter. Size is {} ",
762                 filteredGroups == null ? 0 : filteredGroups.size());
763             if (CollectionUtils.isNotEmpty(filteredGroups)) {
764                 MapArtifactDataDefinition instArifacts = null;
765                 if (!instArtifactsMap.containsKey(ciUid)) {
766                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "istance artifacts not found ");
767                     Map<String, ArtifactDataDefinition> deploymentArtifacts = origComp.getDeploymentArtifacts();
768                     instArifacts = new MapArtifactDataDefinition(deploymentArtifacts);
769                     addToscaDataDeepElementsBlockToToscaElement(clonedVertex, EdgeLabelEnum.INST_DEPLOYMENT_ARTIFACTS,
770                         VertexTypeEnum.INST_DEPLOYMENT_ARTIFACTS, instArifacts, ciUid);
771                     instArtifactsMap.put(ciUid, instArifacts);
772                 } else {
773                     instArifacts = instArtifactsMap.get(ciUid);
774                 }
775                 if (instArifacts != null) {
776                     Map<String, ArtifactDataDefinition> instDeplArtifMap = instArifacts.getMapToscaDataDefinition();
777                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "check group dep artifacts. Size is {} ",
778                         instDeplArtifMap == null ? 0 : instDeplArtifMap.values().size());
779                     Map<String, GroupInstanceDataDefinition> groupInstanceToCreate = new HashMap<>();
780                     for (GroupDataDefinition group : filteredGroups) {
781                         CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "create new groupInstance  {} ", group.getName());
782                         GroupInstanceDataDefinition groupInstance = buildGroupInstanceDataDefinition(group, vfInst);
783                         List<String> artifactsUid = new ArrayList<>();
784                         List<String> artifactsId = new ArrayList<>();
785                         if (instDeplArtifMap != null) {
786                             for (ArtifactDataDefinition artifact : instDeplArtifMap.values()) {
787                                 Optional<String> op = group.getArtifacts() == null ? Optional.empty() : group.getArtifacts().stream().filter(p -> p.equals(artifact.getGeneratedFromId())).findAny();
788                                 if (op.isPresent()) {
789                                     artifactsUid.add(artifact.getArtifactUUID());
790                                     artifactsId.add(artifact.getUniqueId());
791                                 }
792                             }
793                         }
794                         groupInstance.setGroupInstanceArtifacts(artifactsId);
795                         groupInstance.setGroupInstanceArtifactsUuid(artifactsUid);
796                         groupInstanceToCreate.put(groupInstance.getName(), groupInstance);
797                     }
798                     if (MapUtils.isNotEmpty(groupInstanceToCreate)) {
799                         instGroups.put(vfInst.getUniqueId(), new MapGroupsDataDefinition(groupInstanceToCreate));
800                     }
801                 }
802             }
803         }
804     }
805
806     private GraphVertex cloneGraphVertexForCheckout(GraphVertex toscaElementVertex, GraphVertex modifierVertex) {
807         GraphVertex nextVersionToscaElementVertex = new GraphVertex();
808         String uniqueId = UniqueIdBuilder.buildComponentUniqueId();
809         Map<GraphPropertyEnum, Object> metadataProperties = new HashMap<>(toscaElementVertex.getMetadataProperties());
810         nextVersionToscaElementVertex.setMetadataProperties(metadataProperties);
811         nextVersionToscaElementVertex.setUniqueId(uniqueId);
812         nextVersionToscaElementVertex.setLabel(toscaElementVertex.getLabel());
813         nextVersionToscaElementVertex.setType(toscaElementVertex.getType());
814         nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.UNIQUE_ID, uniqueId);
815         nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.COMPONENT_TYPE, nextVersionToscaElementVertex.getType().name());
816         String nextVersion = getNextVersion((String) toscaElementVertex.getMetadataProperty(GraphPropertyEnum.VERSION));
817         if (isFirstCheckoutAfterCertification(nextVersion)) {
818             nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.UUID, IdBuilderUtils.generateUUID());
819         }
820         nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.VERSION, nextVersion);
821         nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name());
822         nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.IS_HIGHEST_VERSION, true);
823         if (toscaElementVertex.getType() == ComponentTypeEnum.SERVICE) {
824             nextVersionToscaElementVertex
825                 .addMetadataProperty(GraphPropertyEnum.DISTRIBUTION_STATUS, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name());
826         }
827         if (!MapUtils.isEmpty(toscaElementVertex.getMetadataJson())) {
828             nextVersionToscaElementVertex.setMetadataJson(new HashMap<>(toscaElementVertex.getMetadataJson()));
829             nextVersionToscaElementVertex.updateMetadataJsonWithCurrentMetadataProperties();
830         }
831         long currTime = System.currentTimeMillis();
832         nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.CREATION_DATE, currTime);
833         nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, currTime);
834         nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.USER_ID_CREATOR, modifierVertex.getUniqueId());
835         nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.USER_ID_LAST_UPDATER, modifierVertex.getUniqueId());
836         if (toscaElementVertex.getType() == ComponentTypeEnum.SERVICE) {
837             nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.CONFORMANCE_LEVEL,
838                 ConfigurationManager.getConfigurationManager().getConfiguration().getToscaConformanceLevel());
839         }
840         if (!MapUtils.isEmpty(toscaElementVertex.getJson())) {
841             nextVersionToscaElementVertex.setJson(new HashMap<>(toscaElementVertex.getJson()));
842         }
843         return nextVersionToscaElementVertex;
844     }
845
846     private Either<GraphVertex, StorageOperationStatus> cloneToscaElementForCertify(GraphVertex toscaElementVertex, GraphVertex modifierVertex,
847                                                                                     Integer majorVersion) {
848         return getToscaElementOperation(toscaElementVertex.getLabel())
849             .cloneToscaElement(toscaElementVertex, cloneGraphVertexForCertify(toscaElementVertex, modifierVertex, majorVersion), modifierVertex)
850             .right().map(
851                 status -> logDebugMessageAndReturnStorageOperationStatus(status, "Failed to clone tosca element {} for certification. Status is {}. ",
852                     toscaElementVertex.getUniqueId(), status)).left().bind(
853                 clonedToscaElement -> updateEdgesDeleteNotCertifiedVersionsAndHandlePreviousVersions(clonedToscaElement, toscaElementVertex,
854                     majorVersion));
855     }
856
857     private Either<GraphVertex, StorageOperationStatus> updateEdgesDeleteNotCertifiedVersionsAndHandlePreviousVersions(GraphVertex clonedToscaElement,
858                                                                                                                        GraphVertex toscaElementVertex,
859                                                                                                                        Integer majorVersion) {
860         StorageOperationStatus updateEdgeToCatalog = updateEdgeToCatalogRoot(clonedToscaElement, toscaElementVertex);
861         if (updateEdgeToCatalog != StorageOperationStatus.OK) {
862             return Either.right(updateEdgeToCatalog);
863         } else {
864             Either<List<GraphVertex>, StorageOperationStatus> deleteResultEither = deleteAllPreviousNotCertifiedVersions(toscaElementVertex);
865             if (deleteResultEither == null) {
866                 return Either.right(logDebugMessageAndReturnStorageOperationStatus(StorageOperationStatus.GENERAL_ERROR,
867                     "Failed to delete all previous not certified versions of tosca element {}. Null value returned.",
868                     toscaElementVertex.getUniqueId()));
869             } else {
870                 return deleteResultEither.right().map(status -> logDebugMessageAndReturnStorageOperationStatus(status,
871                     "Failed to delete all previous not certified versions of tosca element {}. Status is {}. ", toscaElementVertex.getUniqueId(),
872                     status)).left().bind(deleteResult -> handlePreviousVersionRelation(clonedToscaElement, deleteResult, majorVersion));
873             }
874         }
875     }
876
877     private Either<GraphVertex, StorageOperationStatus> handlePreviousVersionRelation(GraphVertex clonedToscaElement,
878                                                                                       List<GraphVertex> deletedVersions, Integer majorVersion) {
879         Either<GraphVertex, StorageOperationStatus> result = null;
880         Vertex previousCertifiedToscaElement = null;
881         if (majorVersion > 0) {
882             List<GraphVertex> firstMinorVersionVertex = deletedVersions.stream()
883                 .filter(gv -> getMinorVersion((String) gv.getMetadataProperty(GraphPropertyEnum.VERSION)) == 1).collect(Collectors.toList());
884             if (CollectionUtils.isEmpty(firstMinorVersionVertex)) {
885                 result = Either.right(StorageOperationStatus.NOT_FOUND);
886             } else {
887                 previousCertifiedToscaElement = getPreviousCertifiedToscaElement(firstMinorVersionVertex.get(0));
888                 if (previousCertifiedToscaElement == null) {
889                     result = Either.right(StorageOperationStatus.NOT_FOUND);
890                 }
891             }
892             if (result == null) {
893                 JanusGraphOperationStatus status = janusGraphDao
894                     .createEdge(previousCertifiedToscaElement, clonedToscaElement.getVertex(), EdgeLabelEnum.VERSION, new HashMap<>());
895                 if (status != JanusGraphOperationStatus.OK) {
896                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG,
897                         "Failed to create edge with label {} from vertex {} to tosca element vertex {} on graph. Status is {}. ",
898                         EdgeLabelEnum.VERSION,
899                         null != previousCertifiedToscaElement ? previousCertifiedToscaElement.property(GraphPropertyEnum.UNIQUE_ID.getProperty())
900                             : null,
901                         clonedToscaElement.getUniqueId(), status);
902                     result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status));
903                 }
904             }
905         }
906         if (result == null) {
907             result = Either.left(clonedToscaElement);
908         }
909         return result;
910     }
911
912     private Vertex getPreviousCertifiedToscaElement(GraphVertex graphVertex) {
913         Iterator<Edge> edges = graphVertex.getVertex().edges(Direction.IN, EdgeLabelEnum.VERSION.name());
914         if (edges.hasNext()) {
915             return edges.next().outVertex();
916         }
917         return null;
918     }
919
920     private Either<List<GraphVertex>, StorageOperationStatus> deleteAllPreviousNotCertifiedVersions(GraphVertex toscaElementVertex) {
921         Either<List<GraphVertex>, StorageOperationStatus> result = null;
922         ToscaElementOperation operation = getToscaElementOperation(toscaElementVertex.getLabel());
923         List<GraphVertex> previosVersions = null;
924         Object uuid = toscaElementVertex.getMetadataProperty(GraphPropertyEnum.UUID);
925         Object componentName = toscaElementVertex.getMetadataProperty(GraphPropertyEnum.NAME);
926         try {
927             Map<GraphPropertyEnum, Object> properties = new HashMap<>();
928             properties.put(GraphPropertyEnum.UUID, uuid);
929             properties.put(GraphPropertyEnum.NAME, componentName);
930             Either<List<GraphVertex>, JanusGraphOperationStatus> getToscaElementsRes = janusGraphDao
931                 .getByCriteria(toscaElementVertex.getLabel(), properties, JsonParseFlagEnum.ParseMetadata);
932             if (getToscaElementsRes.isRight()) {
933                 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(getToscaElementsRes.right().value()));
934             }
935             if (result == null) {
936                 previosVersions = getToscaElementsRes.left().value();
937                 Either<Boolean, StorageOperationStatus> deleteResult = markToscaElementsAsDeleted(operation, getToscaElementsRes.left().value());
938                 if (deleteResult.isRight()) {
939                     result = Either.right(deleteResult.right().value());
940                 }
941             }
942             if (result == null) {
943                 result = Either.left(previosVersions);
944             }
945         } catch (Exception e) {
946             CommonUtility
947                 .addRecordToLog(log, LogLevelEnum.DEBUG, "Exception occurred during deleting all tosca elements by UUID {} and name {}. {} ", uuid,
948                     componentName, e.getMessage());
949         }
950         return result;
951     }
952
953     private GraphVertex cloneGraphVertexForCertify(GraphVertex toscaElementVertex, GraphVertex modifierVertex, Integer majorVersion) {
954         GraphVertex nextVersionToscaElementVertex = new GraphVertex();
955         String uniqueId = IdBuilderUtils.generateUniqueId();
956         Map<GraphPropertyEnum, Object> metadataProperties = new EnumMap<>(toscaElementVertex.getMetadataProperties());
957         nextVersionToscaElementVertex.setMetadataProperties(metadataProperties);
958         nextVersionToscaElementVertex.setUniqueId(uniqueId);
959         nextVersionToscaElementVertex.setLabel(toscaElementVertex.getLabel());
960         nextVersionToscaElementVertex.setType(toscaElementVertex.getType());
961         nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.UNIQUE_ID, uniqueId);
962         nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.COMPONENT_TYPE, nextVersionToscaElementVertex.getType().name());
963         nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.VERSION, (majorVersion + 1) + VERSION_DELIMITER + "0");
964         nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.STATE, LifecycleStateEnum.CERTIFIED.name());
965         nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.IS_HIGHEST_VERSION, true);
966         nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.CREATION_DATE, System.currentTimeMillis());
967         nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, null);
968         nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.USER_ID_CREATOR, modifierVertex.getUniqueId());
969         nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.USER_ID_LAST_UPDATER, modifierVertex.getUniqueId());
970         if (toscaElementVertex.getType() == ComponentTypeEnum.SERVICE) {
971             nextVersionToscaElementVertex
972                 .addMetadataProperty(GraphPropertyEnum.DISTRIBUTION_STATUS, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name());
973         }
974         if (!MapUtils.isEmpty(toscaElementVertex.getMetadataJson())) {
975             nextVersionToscaElementVertex.setMetadataJson(new HashMap<>(toscaElementVertex.getMetadataJson()));
976             nextVersionToscaElementVertex.updateMetadataJsonWithCurrentMetadataProperties();
977         }
978         if (!MapUtils.isEmpty(toscaElementVertex.getJson())) {
979             nextVersionToscaElementVertex.setJson(new HashMap<>(toscaElementVertex.getJson()));
980         }
981         return nextVersionToscaElementVertex;
982     }
983
984     private Either<GraphVertex, StorageOperationStatus> checkinToscaELement(GraphVertex toscaElementVertex,
985                                                                             GraphVertex ownerVertex, GraphVertex modifierVertex,
986                                                                             LifecycleStateEnum nextState) {
987         Either<GraphVertex, StorageOperationStatus> updateRelationsRes;
988         Either<GraphVertex, StorageOperationStatus> result = changeStateToCheckedIn(toscaElementVertex, ownerVertex, modifierVertex);
989         if (result.isLeft()) {
990             toscaElementVertex.addMetadataProperty(GraphPropertyEnum.STATE, nextState.name());
991             toscaElementVertex.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, System.currentTimeMillis());
992             result = updateToscaElementVertexMetadataPropertiesAndJson(toscaElementVertex);
993         }
994         if (result.isLeft()) {
995             updateRelationsRes = updateLastModifierEdge(toscaElementVertex, ownerVertex, modifierVertex);
996             if (updateRelationsRes.isRight()) {
997                 result = Either.right(updateRelationsRes.right().value());
998             }
999         }
1000         return result;
1001     }
1002
1003     private Either<GraphVertex, StorageOperationStatus> updateToscaElementVertexMetadataPropertiesAndJson(GraphVertex toscaElementVertex) {
1004         Either<GraphVertex, StorageOperationStatus> result;
1005         Either<GraphVertex, JanusGraphOperationStatus> updateVertexRes = janusGraphDao.updateVertex(toscaElementVertex);
1006         if (updateVertexRes.isRight()) {
1007             JanusGraphOperationStatus titatStatus = updateVertexRes.right().value();
1008             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update state of tosca element vertex {} metadata. Status is  {}",
1009                 toscaElementVertex.getUniqueId(), titatStatus);
1010             result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(titatStatus));
1011         } else {
1012             result = Either.left(updateVertexRes.left().value());
1013         }
1014         return result;
1015     }
1016
1017     private Either<GraphVertex, StorageOperationStatus> changeStateToCheckedIn(GraphVertex toscaElementVertex,
1018                                                                                GraphVertex ownerVertex, GraphVertex modifierVertex) {
1019         Either<GraphVertex, StorageOperationStatus> result = null;
1020         LifecycleStateEnum nextState = LifecycleStateEnum.NOT_CERTIFIED_CHECKIN;
1021         String faileToUpdateStateMsg = "Failed to update state of tosca element {}. Status is  {}";
1022         // Remove CHECKOUT relation
1023         Either<Edge, JanusGraphOperationStatus> deleteEdgeResult = janusGraphDao.deleteEdge(ownerVertex, toscaElementVertex, EdgeLabelEnum.STATE);
1024         if (deleteEdgeResult.isRight()) {
1025             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, faileToUpdateStateMsg, toscaElementVertex.getUniqueId());
1026             result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(deleteEdgeResult.right().value()));
1027         }
1028         if (result == null) {
1029             // Create CHECKIN relation
1030             Map<EdgePropertyEnum, Object> edgeProperties = new EnumMap<>(EdgePropertyEnum.class);
1031             edgeProperties.put(EdgePropertyEnum.STATE, nextState);
1032             JanusGraphOperationStatus createEdgeRes = janusGraphDao
1033                 .createEdge(modifierVertex.getVertex(), toscaElementVertex.getVertex(), EdgeLabelEnum.STATE, edgeProperties);
1034             if (createEdgeRes != JanusGraphOperationStatus.OK) {
1035                 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, faileToUpdateStateMsg, toscaElementVertex.getUniqueId());
1036                 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(createEdgeRes));
1037             }
1038         }
1039         if (result == null) {
1040             result = Either.left(toscaElementVertex);
1041         }
1042         return result;
1043     }
1044
1045     private Either<GraphVertex, StorageOperationStatus> updateLastModifierEdge(GraphVertex toscaElementVertex, GraphVertex ownerVertex,
1046                                                                                GraphVertex modifierVertex) {
1047         Either<GraphVertex, StorageOperationStatus> result = null;
1048         if (!modifierVertex.getMetadataProperties().get(GraphPropertyEnum.USERID)
1049             .equals(ownerVertex.getMetadataProperties().get(GraphPropertyEnum.USERID))) {
1050             Either<Edge, JanusGraphOperationStatus> deleteEdgeRes = janusGraphDao
1051                 .deleteEdge(ownerVertex, toscaElementVertex, EdgeLabelEnum.LAST_MODIFIER);
1052             if (deleteEdgeRes.isRight()) {
1053                 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to delete last modifier {} to tosca element {}. Edge type is {}",
1054                     ownerVertex.getUniqueId(), ownerVertex.getUniqueId(), EdgeLabelEnum.LAST_MODIFIER);
1055                 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(deleteEdgeRes.right().value()));
1056             }
1057             if (result == null) {
1058                 JanusGraphOperationStatus createEdgeRes = janusGraphDao
1059                     .createEdge(modifierVertex.getVertex(), toscaElementVertex.getVertex(), EdgeLabelEnum.LAST_MODIFIER, new HashMap<>());
1060                 if (createEdgeRes != JanusGraphOperationStatus.OK) {
1061                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to associate user {} to component {}. Edge type is {}",
1062                         modifierVertex.getUniqueId(), ownerVertex.getUniqueId(), EdgeLabelEnum.LAST_MODIFIER);
1063                     result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(createEdgeRes));
1064                 } else {
1065                     result = Either.left(modifierVertex);
1066                 }
1067             }
1068         } else {
1069             result = Either.left(ownerVertex);
1070         }
1071         return result;
1072     }
1073
1074     private Map<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> prepareParametersToGetVerticesForCheckin(String toscaElementId,
1075                                                                                                                       String modifierId,
1076                                                                                                                       String ownerId) {
1077         Map<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> verticesToGetParameters = new HashMap<>();
1078         verticesToGetParameters.put(toscaElementId, new ImmutablePair<>(GraphPropertyEnum.UNIQUE_ID, JsonParseFlagEnum.ParseMetadata));
1079         verticesToGetParameters.put(modifierId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse));
1080         verticesToGetParameters.put(ownerId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse));
1081         return verticesToGetParameters;
1082     }
1083
1084     private Map<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> prepareParametersToGetVerticesForRequestCertification(
1085         String toscaElementId, String modifierId, String ownerId) {
1086         Map<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> verticesToGetParameters = new HashMap<>();
1087         verticesToGetParameters.put(toscaElementId, new ImmutablePair<>(GraphPropertyEnum.UNIQUE_ID, JsonParseFlagEnum.ParseAll));
1088         verticesToGetParameters.put(modifierId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse));
1089         verticesToGetParameters.put(ownerId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse));
1090         return verticesToGetParameters;
1091     }
1092
1093     private Map<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> prepareParametersToGetVerticesForCheckout(String toscaElementId,
1094                                                                                                                        String modifierId,
1095                                                                                                                        String ownerId) {
1096         //Implementation is currently identical
1097         return prepareParametersToGetVerticesForRequestCertification(toscaElementId, modifierId, ownerId);
1098     }
1099
1100     private String getNextCertifiedVersion(String version) {
1101         String[] versionParts = version.split(VERSION_DELIMITER_REGEXP);
1102         Integer nextMajorVersion = Integer.parseInt(versionParts[0]) + 1;
1103         return nextMajorVersion + VERSION_DELIMITER + "0";
1104     }
1105
1106     private String getNextVersion(String currVersion) {
1107         String[] versionParts = currVersion.split(VERSION_DELIMITER_REGEXP);
1108         Integer minorVersion = Integer.parseInt(versionParts[1]) + 1;
1109         return versionParts[0] + VERSION_DELIMITER + minorVersion;
1110     }
1111
1112     private Integer getMinorVersion(String version) {
1113         String[] versionParts = version.split(VERSION_DELIMITER_REGEXP);
1114         return Integer.parseInt(versionParts[1]);
1115     }
1116
1117     private Integer getMajorVersion(String version) {
1118         String[] versionParts = version.split(VERSION_DELIMITER_REGEXP);
1119         return Integer.parseInt(versionParts[0]);
1120     }
1121
1122     private boolean isFirstCheckoutAfterCertification(String version) {
1123         return (Integer.parseInt(version.split(VERSION_DELIMITER_REGEXP)[0]) != 0
1124             && Integer.parseInt(version.split(VERSION_DELIMITER_REGEXP)[1]) == 1);
1125     }
1126
1127     public Either<ToscaElement, StorageOperationStatus> forceCerificationOfToscaElement(String toscaElementId, String modifierId, String ownerId,
1128                                                                                         String currVersion) {
1129         Either<GraphVertex, StorageOperationStatus> resultUpdate = null;
1130         Either<ToscaElement, StorageOperationStatus> result = null;
1131         GraphVertex toscaElement = null;
1132         GraphVertex modifier = null;
1133         GraphVertex owner;
1134         try {
1135             Either<Map<String, GraphVertex>, JanusGraphOperationStatus> getVerticesRes = janusGraphDao
1136                 .getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForRequestCertification(toscaElementId, modifierId, ownerId));
1137             if (getVerticesRes.isRight()) {
1138                 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId);
1139                 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(getVerticesRes.right().value()));
1140             }
1141             if (result == null) {
1142                 toscaElement = getVerticesRes.left().value().get(toscaElementId);
1143                 modifier = getVerticesRes.left().value().get(modifierId);
1144                 owner = getVerticesRes.left().value().get(ownerId);
1145                 StorageOperationStatus status = handleRelationsUponForceCertification(toscaElement, modifier, owner);
1146                 if (status != StorageOperationStatus.OK) {
1147                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG,
1148                         "Failed to handle relations on certification request for tosca element {}. Status is {}. ", toscaElement.getUniqueId(),
1149                         status);
1150                 }
1151             }
1152             if (result == null) {
1153                 LifecycleStateEnum nextState = LifecycleStateEnum.CERTIFIED;
1154                 toscaElement.addMetadataProperty(GraphPropertyEnum.STATE, LifecycleStateEnum.CERTIFIED.name());
1155                 toscaElement.addMetadataProperty(GraphPropertyEnum.VERSION, getNextCertifiedVersion(currVersion));
1156                 resultUpdate = updateToscaElementVertexMetadataPropertiesAndJson(toscaElement);
1157                 if (resultUpdate.isRight()) {
1158                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to set lifecycle for tosca elememt {} to state {}, error: {}",
1159                         toscaElement.getUniqueId(), nextState, resultUpdate.right().value());
1160                     result = Either.right(resultUpdate.right().value());
1161                 }
1162             }
1163             if (result == null) {
1164                 ToscaElementOperation operation = getToscaElementOperation(toscaElement.getLabel());
1165                 result = operation.getToscaElement(toscaElement.getUniqueId());
1166             }
1167             return result;
1168         } catch (Exception e) {
1169             CommonUtility
1170                 .addRecordToLog(log, LogLevelEnum.DEBUG, "Exception occured during request certification tosca element {}. {}", toscaElementId,
1171                     e.getMessage());
1172         }
1173         return result;
1174     }
1175
1176     private StorageOperationStatus handleRelationsUponForceCertification(GraphVertex toscaElement, GraphVertex modifier, GraphVertex owner) {
1177         StorageOperationStatus result = null;
1178         JanusGraphOperationStatus status = janusGraphDao
1179             .replaceEdgeLabel(owner.getVertex(), toscaElement.getVertex(), EdgeLabelEnum.STATE, EdgeLabelEnum.LAST_STATE);
1180         if (status != JanusGraphOperationStatus.OK) {
1181             result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status);
1182         }
1183         if (result == null) {
1184             Map<EdgePropertyEnum, Object> properties = new EnumMap<>(EdgePropertyEnum.class);
1185             properties.put(EdgePropertyEnum.STATE, LifecycleStateEnum.CERTIFIED);
1186             status = janusGraphDao.createEdge(modifier, toscaElement, EdgeLabelEnum.STATE, properties);
1187             if (status != JanusGraphOperationStatus.OK) {
1188                 CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "failed to create edge. Status is {}", status);
1189                 result = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status);
1190             }
1191         }
1192         if (result == null) {
1193             result = StorageOperationStatus.OK;
1194         }
1195         return result;
1196     }
1197
1198     private StorageOperationStatus updateEdgeToCatalogRootByUndoCheckout(JanusGraphVertex preV, GraphVertex curV) {
1199         if (preV == null) {
1200             return updateEdgeToCatalogRoot(null, curV);
1201         }
1202         String uniqueIdPreVer = (String) janusGraphDao.getProperty(preV, GraphPropertyEnum.UNIQUE_ID.getProperty());
1203         LifecycleStateEnum state = LifecycleStateEnum.findState((String) janusGraphDao.getProperty(preV, GraphPropertyEnum.STATE.getProperty()));
1204         if (state == LifecycleStateEnum.CERTIFIED) {
1205             return updateEdgeToCatalogRoot(null, curV);
1206         }
1207         return janusGraphDao.getVertexById(uniqueIdPreVer)
1208             .either(l -> updateEdgeToCatalogRoot(l, curV), DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
1209     }
1210
1211     private StorageOperationStatus updateEdgeToCatalogRoot(GraphVertex newVersionV, GraphVertex prevVersionV) {
1212         Either<GraphVertex, JanusGraphOperationStatus> catalog = janusGraphDao.getVertexByLabel(VertexTypeEnum.CATALOG_ROOT);
1213         if (catalog.isRight()) {
1214             CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to fetch catalog vertex. error {}", catalog.right().value());
1215             return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(catalog.right().value());
1216         }
1217         GraphVertex catalogV = catalog.left().value();
1218         if (newVersionV != null) {
1219             Boolean isAbstract = (Boolean) newVersionV.getMetadataProperty(GraphPropertyEnum.IS_ABSTRACT);
1220             if (isAbstract == null || !isAbstract) {
1221                 // create new vertex
1222                 JanusGraphOperationStatus result = janusGraphDao.createEdge(catalogV, newVersionV, EdgeLabelEnum.CATALOG_ELEMENT, null);
1223                 if (result != JanusGraphOperationStatus.OK) {
1224                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to create edge from {} to catalog vertex. error {}",
1225                         newVersionV.getUniqueId(), result);
1226                     return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(result);
1227                 }
1228             }
1229         }
1230         if (prevVersionV != null) {
1231             Boolean isAbstract = (Boolean) prevVersionV.getMetadataProperty(GraphPropertyEnum.IS_ABSTRACT);
1232             if (isAbstract == null || !isAbstract) {
1233                 // if prev == null -> new resource was added
1234                 Either<Edge, JanusGraphOperationStatus> deleteResult = janusGraphDao
1235                     .deleteEdge(catalogV, prevVersionV, EdgeLabelEnum.CATALOG_ELEMENT);
1236                 if (deleteResult.isRight()) {
1237                     CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to delete edge from {} to catalog vertex. error {}",
1238                         prevVersionV.getUniqueId(), deleteResult.right().value());
1239                     return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(deleteResult.right().value());
1240                 }
1241             }
1242         }
1243         return StorageOperationStatus.OK;
1244     }
1245 }