Sync Integ to Master
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / lifecycle / LifecycleBusinessLogic.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
21 package org.openecomp.sdc.be.components.lifecycle;
22
23 import fj.data.Either;
24 import org.openecomp.sdc.be.components.distribution.engine.ServiceDistributionArtifactsBuilder;
25 import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic;
26 import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic;
27 import org.openecomp.sdc.be.components.impl.ProductBusinessLogic;
28 import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic;
29 import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic;
30 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction.LifecycleChanceActionEnum;
31 import org.openecomp.sdc.be.dao.api.ActionStatus;
32 import org.openecomp.sdc.be.dao.jsongraph.TitanDao;
33 import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition;
34 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
35 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
36 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
37 import org.openecomp.sdc.be.impl.ComponentsUtils;
38 import org.openecomp.sdc.be.model.Component;
39 import org.openecomp.sdc.be.model.LifeCycleTransitionEnum;
40 import org.openecomp.sdc.be.model.LifecycleStateEnum;
41 import org.openecomp.sdc.be.model.Resource;
42 import org.openecomp.sdc.be.model.Service;
43 import org.openecomp.sdc.be.model.User;
44 import org.openecomp.sdc.be.model.jsontitan.datamodel.ToscaElement;
45 import org.openecomp.sdc.be.model.jsontitan.operations.ToscaElementLifecycleOperation;
46 import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade;
47 import org.openecomp.sdc.be.model.jsontitan.utils.ModelConverter;
48 import org.openecomp.sdc.be.model.operations.api.ICacheMangerOperation;
49 import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation;
50 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
51 import org.openecomp.sdc.be.model.operations.impl.CapabilityOperation;
52 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
53 import org.openecomp.sdc.be.resources.data.auditing.model.ResourceAuditData;
54 import org.openecomp.sdc.be.tosca.ToscaExportHandler;
55 import org.openecomp.sdc.common.api.Constants;
56 import org.openecomp.sdc.common.util.ValidationUtils;
57 import org.openecomp.sdc.exception.ResponseFormat;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60 import org.springframework.beans.factory.annotation.Autowired;
61
62 import javax.annotation.PostConstruct;
63 import java.util.HashMap;
64 import java.util.Map;
65
66 @org.springframework.stereotype.Component("lifecycleBusinessLogic")
67 public class LifecycleBusinessLogic {
68
69     private static final String COMMENT = "comment";
70
71     @Autowired
72     private IGraphLockOperation graphLockOperation = null;
73
74     @Autowired
75     private ArtifactsBusinessLogic artifactsBusinessLogic;
76
77     @Autowired
78     private TitanDao titanDao;
79
80     @Autowired
81     private CapabilityOperation capabilityOperation;
82
83     private static final Logger log = LoggerFactory.getLogger(LifecycleBusinessLogic.class);
84
85     @javax.annotation.Resource
86     private ComponentsUtils componentUtils;
87
88     @javax.annotation.Resource
89     private ToscaElementLifecycleOperation lifecycleOperation;
90     @javax.annotation.Resource
91     ArtifactsBusinessLogic artifactsManager;
92
93     @javax.annotation.Resource
94     private ServiceDistributionArtifactsBuilder serviceDistributionArtifactsBuilder;
95
96     @javax.annotation.Resource
97     private ServiceBusinessLogic serviceBusinessLogic;
98
99     @javax.annotation.Resource
100     private ResourceBusinessLogic resourceBusinessLogic;
101
102     @javax.annotation.Resource
103     private ProductBusinessLogic productBusinessLogic;
104
105     @Autowired
106     private ToscaExportHandler toscaExportUtils;
107
108     @Autowired
109     ICacheMangerOperation cacheManagerOperation;
110
111     @Autowired
112     ToscaOperationFacade toscaOperationFacade;
113
114     private Map<String, LifeCycleTransition> stateTransitions;
115     private static volatile boolean isInitialized = false;
116
117     @PostConstruct
118     public void init() {
119         // init parameters
120         if (!isInitialized) {
121             synchronized (this) {
122                 if (!isInitialized) {
123                     initStateOperations();
124                     isInitialized = true;
125                 }
126             }
127         }
128     }
129
130     private void initStateOperations() {
131         stateTransitions = new HashMap<String, LifeCycleTransition>();
132
133         LifeCycleTransition checkoutOp = new CheckoutTransition(componentUtils, lifecycleOperation, toscaOperationFacade, titanDao);
134         stateTransitions.put(checkoutOp.getName().name(), checkoutOp);
135
136         UndoCheckoutTransition undoCheckoutOp = new UndoCheckoutTransition(componentUtils, lifecycleOperation, toscaOperationFacade, titanDao);
137         undoCheckoutOp.setArtifactsBusinessLogic(artifactsBusinessLogic);
138         stateTransitions.put(undoCheckoutOp.getName().name(), undoCheckoutOp);
139
140         LifeCycleTransition checkinOp = new CheckinTransition(componentUtils, lifecycleOperation, toscaOperationFacade, titanDao);
141         stateTransitions.put(checkinOp.getName().name(), checkinOp);
142
143         LifeCycleTransition certificationRequest = new CertificationRequestTransition(componentUtils, lifecycleOperation, serviceDistributionArtifactsBuilder, serviceBusinessLogic, capabilityOperation, toscaExportUtils, toscaOperationFacade, titanDao);
144         stateTransitions.put(certificationRequest.getName().name(), certificationRequest);
145
146         LifeCycleTransition startCertification = new StartCertificationTransition(componentUtils, lifecycleOperation, toscaOperationFacade, titanDao);
147         stateTransitions.put(startCertification.getName().name(), startCertification);
148
149         LifeCycleTransition failCertification = new CertificationChangeTransition(LifeCycleTransitionEnum.FAIL_CERTIFICATION, componentUtils, lifecycleOperation, toscaOperationFacade, titanDao);
150         stateTransitions.put(failCertification.getName().name(), failCertification);
151
152         LifeCycleTransition cancelCertification = new CertificationChangeTransition(LifeCycleTransitionEnum.CANCEL_CERTIFICATION, componentUtils, lifecycleOperation, toscaOperationFacade, titanDao);
153         stateTransitions.put(cancelCertification.getName().name(), cancelCertification);
154
155         CertificationChangeTransition successCertification = new CertificationChangeTransition(LifeCycleTransitionEnum.CERTIFY, componentUtils, lifecycleOperation, toscaOperationFacade, titanDao);
156         successCertification.setArtifactsManager(artifactsBusinessLogic);
157         stateTransitions.put(successCertification.getName().name(), successCertification);
158     }
159
160     public LifeCycleTransition getLifecycleTransition(LifeCycleTransitionEnum transitionEnum) {
161         return stateTransitions.get(transitionEnum.name());
162     }
163
164     public Either<Service, ResponseFormat> changeServiceState(String serviceId, User modifier, LifeCycleTransitionEnum transitionEnum, LifecycleChangeInfoWithAction changeInfo, boolean inTransaction, boolean needLock) {
165         return (Either<Service, ResponseFormat>) changeComponentState(ComponentTypeEnum.SERVICE, serviceId, modifier, transitionEnum, changeInfo, inTransaction, needLock);
166     }
167
168     // TODO: rhalili - should use changeComponentState when possible
169     public Either<Resource, ResponseFormat> changeState(String resourceId, User modifier, LifeCycleTransitionEnum transitionEnum, LifecycleChangeInfoWithAction changeInfo, boolean inTransaction, boolean needLock) {
170         return (Either<Resource, ResponseFormat>) changeComponentState(ComponentTypeEnum.RESOURCE, resourceId, modifier, transitionEnum, changeInfo, inTransaction, needLock);
171     }
172
173     private boolean isComponentVFCMT(Component component, ComponentTypeEnum componentType){
174         if (componentType.equals(ComponentTypeEnum.RESOURCE)){
175             ResourceTypeEnum resourceType = ((ResourceMetadataDataDefinition)component.getComponentMetadataDefinition().getMetadataDataDefinition()).getResourceType();
176             if (resourceType.equals(ResourceTypeEnum.VFCMT)){
177                 return true;
178             }
179         }
180         return false;
181     }
182
183     public Either<? extends Component, ResponseFormat> changeComponentState(ComponentTypeEnum componentType, String componentId, User modifier, LifeCycleTransitionEnum transitionEnum, LifecycleChangeInfoWithAction changeInfo, boolean inTransaction,
184             boolean needLock) {
185
186         LifeCycleTransition lifeCycleTransition = stateTransitions.get(transitionEnum.name());
187         if (lifeCycleTransition == null) {
188             log.debug("state operation is not valid. operations allowed are: {}", LifeCycleTransitionEnum.valuesAsString());
189             ResponseFormat error = componentUtils.getInvalidContentErrorAndAudit(modifier,componentId, AuditingActionEnum.CHECKOUT_RESOURCE);
190             return Either.right(error);
191         }
192         Component component = null;
193         log.info("get resource from graph");
194         ResponseFormat errorResponse;
195
196         Either<? extends Component, ResponseFormat> eitherResourceResponse = getComponentForChange(componentType, componentId, modifier, lifeCycleTransition, changeInfo);
197         if (eitherResourceResponse.isRight()) {
198             return eitherResourceResponse;
199         }
200         component = eitherResourceResponse.left().value();
201         String resourceCurrVersion = component.getVersion();
202         LifecycleStateEnum resourceCurrState = component.getLifecycleState();
203
204         // lock resource
205         if (!inTransaction && needLock) {
206             log.info("lock component {}", componentId);
207             Either<Boolean, ResponseFormat> eitherLockResource = lockComponent(componentType, component);
208             if (eitherLockResource.isRight()) {
209                 errorResponse = eitherLockResource.right().value();
210                 componentUtils.auditComponent(errorResponse, modifier, component, lifeCycleTransition.getAuditingAction(), componentType,
211                         ResourceAuditData.newBuilder().state(resourceCurrState.name()).version(resourceCurrVersion).build());
212
213                 log.error("lock component {} failed", componentId);
214                 return Either.right(errorResponse);
215             }
216             log.debug("after lock component {}", componentId);
217         }
218         try {
219             Either<String, ResponseFormat> commentValidationResult = validateComment(changeInfo, transitionEnum);
220             if (commentValidationResult.isRight()) {
221                 errorResponse = commentValidationResult.right().value();
222                 componentUtils.auditComponent(errorResponse, modifier, component, lifeCycleTransition.getAuditingAction(), componentType,
223                         ResourceAuditData.newBuilder()
224                                 .state(resourceCurrState.name()).version(resourceCurrVersion).build(), changeInfo.getUserRemarks());
225                 return Either.right(errorResponse);
226             }
227             changeInfo.setUserRemarks(commentValidationResult.left().value());
228             log.debug("after validate component");
229             Either<Boolean, ResponseFormat> validateHighestVersion = validateHighestVersion(modifier, lifeCycleTransition, component, resourceCurrVersion, componentType);
230             if (validateHighestVersion.isRight()) {
231                 return Either.right(validateHighestVersion.right().value());
232             }
233             log.debug("after validate Highest Version");
234             if (isComponentVFCMT(component,componentType)){
235                 Either<? extends Component, ResponseFormat> changeVFCMTStateResponse = changeVFCMTState(componentType, modifier, transitionEnum, changeInfo, true, component);
236                 if (changeVFCMTStateResponse.isRight()){
237                     return changeVFCMTStateResponse;
238                 }
239                 component = changeVFCMTStateResponse.left().value();
240             }
241             return changeState(component, lifeCycleTransition, componentType, modifier, changeInfo, inTransaction);
242         } finally {
243             component.setUniqueId(componentId);
244             if (!inTransaction && needLock) {
245                 log.info("unlock component {}", componentId);
246                 NodeTypeEnum nodeType = componentType.getNodeType();
247                 log.info("During change state, another component {} has been created/updated", componentId);
248                 graphLockOperation.unlockComponent(componentId, nodeType);
249
250             }
251         }
252
253     }
254
255     /*
256      * special case for certification of VFCMT - VFCMT can be certified by Designer or Tester right after checkin
257      * in case the operation "submit for test" / "start testing" is done to "VFCMT" - please return error 400
258      */
259     private Either<? extends Component, ResponseFormat> changeVFCMTState(ComponentTypeEnum componentType, User modifier,
260             LifeCycleTransitionEnum transitionEnum, LifecycleChangeInfoWithAction changeInfo, boolean inTransaction,
261             Component component) {
262         LifecycleStateEnum oldState = component.getLifecycleState();
263         Component updatedComponent = component;
264         if (transitionEnum.equals(LifeCycleTransitionEnum.START_CERTIFICATION) ||
265                 transitionEnum.equals(LifeCycleTransitionEnum.CERTIFICATION_REQUEST)){
266             return Either.right(componentUtils.getResponseFormat(
267                     ActionStatus.RESOURCE_VFCMT_LIFECYCLE_STATE_NOT_VALID, transitionEnum.getDisplayName()));
268         }    //certify is done directly from checkin
269         else if (transitionEnum.equals(LifeCycleTransitionEnum.CERTIFY) && oldState.equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN)){
270             //we will call for submit for testing first and then for certify
271             Either<? extends Component, ResponseFormat> actionResponse = changeState(component,
272                     stateTransitions.get(LifeCycleTransitionEnum.CERTIFICATION_REQUEST.name()),
273                     componentType, modifier, changeInfo, inTransaction);
274             if (actionResponse.isRight()) {
275                 return actionResponse;
276             }
277             updatedComponent = actionResponse.left().value();
278             actionResponse = changeState(updatedComponent,
279                     stateTransitions.get(LifeCycleTransitionEnum.START_CERTIFICATION.name()),
280                     componentType, modifier, changeInfo, inTransaction);
281             if (actionResponse.isRight()) {
282                 return actionResponse;
283             }
284             updatedComponent = actionResponse.left().value();
285              
286         }
287         return Either.left(updatedComponent);
288     }
289
290     private Either<? extends Component, ResponseFormat> changeState(Component component, LifeCycleTransition lifeCycleTransition,
291             ComponentTypeEnum componentType, User modifier,    LifecycleChangeInfoWithAction changeInfo,boolean inTransaction){
292         ResponseFormat errorResponse;
293
294         LifecycleStateEnum oldState = component.getLifecycleState();
295         String resourceCurrVersion = component.getVersion();
296         ComponentBusinessLogic bl = getComponentBL(componentType);
297
298         Either<User, ResponseFormat> ownerResult = lifeCycleTransition.getComponentOwner(component, componentType, inTransaction);
299         if (ownerResult.isRight()) {
300             return Either.right(ownerResult.right().value());
301         }
302         User owner = ownerResult.left().value();
303         log.info("owner of resource {} is {}", component.getUniqueId(), owner.getUserId());
304
305         Either<Boolean, ResponseFormat> stateValidationResult = lifeCycleTransition.validateBeforeTransition(component, componentType, modifier, owner, oldState, changeInfo);
306         if (stateValidationResult.isRight()) {
307             log.error("Failed to validateBeforeTransition");
308             errorResponse = stateValidationResult.right().value();
309             componentUtils.auditComponent(errorResponse, modifier, component, lifeCycleTransition.getAuditingAction(), componentType,
310                     ResourceAuditData.newBuilder().version(resourceCurrVersion).state(oldState.name()).build(), changeInfo.getUserRemarks());
311             return Either.right(errorResponse);
312         }
313
314         Either<? extends Component, ResponseFormat> operationResult = lifeCycleTransition.changeState(componentType, component, bl, modifier, owner, false, inTransaction);
315
316         if (operationResult.isRight()) {
317             errorResponse = operationResult.right().value();
318             log.info("audit before sending error response");
319             componentUtils.auditComponentAdmin(errorResponse, modifier, component, lifeCycleTransition.getAuditingAction(), componentType,
320                      ResourceAuditData.newBuilder().state(oldState.name()).version(resourceCurrVersion).build());
321
322             return Either.right(errorResponse);
323         }
324         Component resourceAfterOperation = operationResult.left().value();
325         componentUtils.auditComponent(componentUtils.getResponseFormat(ActionStatus.OK), modifier, resourceAfterOperation, lifeCycleTransition.getAuditingAction(), componentType,
326                 ResourceAuditData.newBuilder().state(oldState.name()).version(resourceCurrVersion).build(), changeInfo.getUserRemarks());
327         return operationResult;
328
329     }
330
331     private Either<? extends Component, ResponseFormat> getComponentForChange(ComponentTypeEnum componentType, String componentId, User modifier, LifeCycleTransition lifeCycleTransition, LifecycleChangeInfoWithAction changeInfo) {
332
333         Either<? extends Component, StorageOperationStatus> eitherResourceResponse = toscaOperationFacade.getToscaElement(componentId);
334
335         ResponseFormat errorResponse;
336         if (eitherResourceResponse.isRight()) {
337             ActionStatus actionStatus = componentUtils.convertFromStorageResponse(eitherResourceResponse.right().value(), componentType);
338             errorResponse = componentUtils.getResponseFormat(actionStatus, Constants.EMPTY_STRING);
339             log.debug("audit before sending response");
340             componentUtils.auditComponent(errorResponse, modifier, lifeCycleTransition.getAuditingAction(), componentId, componentType, changeInfo.getUserRemarks());
341
342             return Either.right(errorResponse);
343         }
344         return Either.left(eitherResourceResponse.left().value());
345     }
346
347     private Either<Boolean, ResponseFormat> validateHighestVersion(User modifier, LifeCycleTransition lifeCycleTransition, Resource resource, String resourceCurrVersion) {
348         ResponseFormat errorResponse;
349         if (!resource.isHighestVersion()) {
350             log.debug("resource version {} is not the last version of resource {}", resource.getVersion(), resource.getName());
351             errorResponse = componentUtils.getResponseFormat(ActionStatus.COMPONENT_HAS_NEWER_VERSION, resource.getName(), ComponentTypeEnum.RESOURCE.name().toLowerCase());
352             componentUtils.auditResource(errorResponse, modifier, resource, lifeCycleTransition.getAuditingAction(), ResourceAuditData.newBuilder()
353                     .state(resource.getLifecycleState().name()).version(resourceCurrVersion).build());
354             return Either.right(errorResponse);
355         }
356         return Either.left(true);
357     }
358
359     private Either<Boolean, ResponseFormat> validateHighestVersion(User modifier, LifeCycleTransition lifeCycleTransition, Component component, String resourceCurrVersion, ComponentTypeEnum componentType) {
360         ResponseFormat errorResponse;
361         if (!component.isHighestVersion()) {
362             log.debug("Component version {} is not the last version of component {}", component.getComponentMetadataDefinition().getMetadataDataDefinition().getVersion(),
363                     component.getComponentMetadataDefinition().getMetadataDataDefinition().getName());
364             errorResponse = componentUtils.getResponseFormat(ActionStatus.COMPONENT_HAS_NEWER_VERSION, component.getComponentMetadataDefinition().getMetadataDataDefinition().getName(), componentType.getValue().toLowerCase());
365             componentUtils.auditComponentAdmin(errorResponse, modifier, component,lifeCycleTransition.getAuditingAction(), componentType,
366                     ResourceAuditData.newBuilder().state(component.getLifecycleState().name()).version(resourceCurrVersion).build());
367             return Either.right(errorResponse);
368         }
369         return Either.left(true);
370     }
371
372     private Either<Boolean, ResponseFormat> lockComponent(ComponentTypeEnum componentType, Component component) {
373         NodeTypeEnum nodeType = componentType.getNodeType();
374         StorageOperationStatus lockResourceStatus = graphLockOperation.lockComponent(component.getUniqueId(), nodeType);
375
376         if (lockResourceStatus.equals(StorageOperationStatus.OK)) {
377             return Either.left(true);
378         } else {
379             ActionStatus actionStatus = componentUtils.convertFromStorageResponse(lockResourceStatus);
380             ResponseFormat responseFormat = componentUtils.getResponseFormat(actionStatus, component.getComponentMetadataDefinition().getMetadataDataDefinition().getName());
381             return Either.right(responseFormat);
382         }
383
384     }
385
386     private Either<String, ResponseFormat> validateComment(LifecycleChangeInfoWithAction changeInfo, LifeCycleTransitionEnum transitionEnum) {
387         String comment = changeInfo.getUserRemarks();
388         if (LifeCycleTransitionEnum.CANCEL_CERTIFICATION == transitionEnum || LifeCycleTransitionEnum.CERTIFY == transitionEnum || LifeCycleTransitionEnum.FAIL_CERTIFICATION == transitionEnum || LifeCycleTransitionEnum.CHECKIN == transitionEnum
389                 || LifeCycleTransitionEnum.CERTIFICATION_REQUEST == transitionEnum
390         // import?
391         ) {
392
393             if (!ValidationUtils.validateStringNotEmpty(comment)) {
394                 log.debug("user comment cannot be empty or null.");
395                 ResponseFormat errorResponse = componentUtils.getResponseFormat(ActionStatus.MISSING_DATA, COMMENT);
396                 return Either.right(errorResponse);
397             }
398
399             comment = ValidationUtils.removeNoneUtf8Chars(comment);
400             comment = ValidationUtils.removeHtmlTags(comment);
401             comment = ValidationUtils.normaliseWhitespace(comment);
402             comment = ValidationUtils.stripOctets(comment);
403
404             if (!ValidationUtils.validateLength(comment, ValidationUtils.COMMENT_MAX_LENGTH)) {
405                 log.debug("user comment exceeds limit.");
406                 return Either.right(componentUtils.getResponseFormat(ActionStatus.EXCEEDS_LIMIT, COMMENT, String.valueOf(ValidationUtils.COMMENT_MAX_LENGTH)));
407             }
408             if (!ValidationUtils.validateIsEnglish(comment)) {
409                 return Either.right(componentUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
410             }
411         }
412         return Either.left(comment);
413     }
414
415     private ComponentBusinessLogic getComponentBL(ComponentTypeEnum componentTypeEnum) {
416         ComponentBusinessLogic businessLogic;
417         switch (componentTypeEnum) {
418             case RESOURCE:
419                 businessLogic = this.resourceBusinessLogic;
420                 break;
421             case SERVICE:
422                 businessLogic = this.serviceBusinessLogic;
423                 break;
424             case PRODUCT:
425                 businessLogic = this.productBusinessLogic;
426                 break;
427             default:
428                 throw new IllegalArgumentException("Illegal component type:" + componentTypeEnum.getValue());
429         }
430         return businessLogic;
431     }
432
433     public Either<Component, ResponseFormat> getLatestComponentByUuid(ComponentTypeEnum componentTypeEnum, String uuid) {
434
435         Either<Component, StorageOperationStatus> latestVersionEither = toscaOperationFacade.getLatestComponentByUuid(uuid);
436
437         if (latestVersionEither.isRight()) {
438
439             return Either.right(componentUtils.getResponseFormat(componentUtils.convertFromStorageResponse(latestVersionEither.right().value(), componentTypeEnum), uuid));
440         }
441
442         Component latestComponent = latestVersionEither.left().value();
443
444         return Either.left(latestComponent);
445     }
446 /**
447  * Performs Force certification.
448  * Note that a Force certification is allowed for the first certification only,
449  * as only a state and a version is promoted due a Force certification,
450  * skipping other actions required if a previous certified version exists.
451  * @param resource
452  * @param user
453  * @param lifecycleChangeInfo
454  * @param inTransaction
455  * @param needLock
456  * @return
457  */
458     public Either<Resource, ResponseFormat> forceResourceCertification(Resource resource, User user, LifecycleChangeInfoWithAction lifecycleChangeInfo, boolean inTransaction, boolean needLock) {
459         Either<Resource, ResponseFormat> result = null;
460         Either<ToscaElement, StorageOperationStatus> certifyResourceRes = null;
461         if(lifecycleChangeInfo.getAction() != LifecycleChanceActionEnum.CREATE_FROM_CSAR){
462             log.debug("Force certification is not allowed for the action {}. ", lifecycleChangeInfo.getAction());
463             result = Either.right(componentUtils.getResponseFormat(ActionStatus.NOT_ALLOWED));
464         }
465         if(!isFirstCertification(resource.getVersion())){
466             log.debug("Failed to perform a force certification of resource{}. Force certification is allowed for the first certification only. ", resource.getName());
467             result = Either.right(componentUtils.getResponseFormat(ActionStatus.NOT_ALLOWED));
468         }
469         // lock resource
470         if(result == null && !inTransaction && needLock){
471             log.info("lock component {}", resource.getUniqueId());
472             Either<Boolean, ResponseFormat> eitherLockResource = lockComponent(resource.getComponentType(), resource);
473             if (eitherLockResource.isRight()) {
474                 log.error("lock component {} failed", resource.getUniqueId());
475                 result =  Either.right(eitherLockResource.right().value());
476             }
477             log.info("after lock component {}", resource.getUniqueId());
478         }
479         try{
480             if(result == null){
481                 certifyResourceRes = lifecycleOperation.forceCerificationOfToscaElement(resource.getUniqueId(), user.getUserId(), user.getUserId(), resource.getVersion());
482                 if (certifyResourceRes.isRight()) {
483                     StorageOperationStatus status = certifyResourceRes.right().value();
484                     log.debug("Failed to perform a force certification of resource {}. The status is {}. ", resource.getName(), status);
485                     result = Either.right(componentUtils.getResponseFormatByResource(componentUtils.convertFromStorageResponse(status), resource));
486                 }
487             }
488             if(result == null){
489                 result = Either.left(ModelConverter.convertFromToscaElement(certifyResourceRes.left().value()));
490             }
491         } finally {
492             log.info("unlock component {}", resource.getUniqueId());
493             if (!inTransaction) {
494                 if(result.isLeft()){
495                     titanDao.commit();
496                 } else{
497                     titanDao.rollback();
498                 }
499                 if(needLock){
500                     NodeTypeEnum nodeType = resource.getComponentType().getNodeType();
501                     log.info("During change state, another component {} has been created/updated", resource.getUniqueId());
502                     graphLockOperation.unlockComponent(resource.getUniqueId(), nodeType);
503                 }
504             }
505         }
506         return result;
507     }
508
509     public boolean isFirstCertification(String previousVersion) {
510         return previousVersion.split("\\.")[0].equals("0");
511     }
512
513 }