General sonar fixes
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / InputsBusinessLogic.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  * Modifications copyright (c) 2019 Nokia
20  * ================================================================================
21  */
22
23 package org.openecomp.sdc.be.components.impl;
24
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Objects;
32 import java.util.Optional;
33 import java.util.stream.Collectors;
34 import org.apache.commons.collections4.ListUtils;
35 import org.apache.commons.collections4.MapUtils;
36 import org.apache.commons.lang.BooleanUtils;
37 import org.apache.commons.lang.StringUtils;
38 import org.apache.commons.lang.builder.ReflectionToStringBuilder;
39 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
40 import org.openecomp.sdc.be.components.property.PropertyDeclarationOrchestrator;
41 import org.openecomp.sdc.be.components.validation.ComponentValidations;
42 import org.openecomp.sdc.be.dao.api.ActionStatus;
43 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
44 import org.openecomp.sdc.be.dao.utils.MapUtil;
45 import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil;
46 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
47 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
48 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
49 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
50 import org.openecomp.sdc.be.model.ComponentInstInputsMap;
51 import org.openecomp.sdc.be.model.ComponentInstListInput;
52 import org.openecomp.sdc.be.model.ComponentInstance;
53 import org.openecomp.sdc.be.model.ComponentInstanceInput;
54 import org.openecomp.sdc.be.model.ComponentInstancePropInput;
55 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
56 import org.openecomp.sdc.be.model.ComponentParametersView;
57 import org.openecomp.sdc.be.model.DataTypeDefinition;
58 import org.openecomp.sdc.be.model.InputDefinition;
59 import org.openecomp.sdc.be.model.PropertyDefinition;
60 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
61 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
62 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
63 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
64 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
65 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
66 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
67 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
68 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
69 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
70 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
71 import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
72 import org.openecomp.sdc.common.log.wrappers.Logger;
73 import org.openecomp.sdc.exception.ResponseFormat;
74 import org.springframework.beans.factory.annotation.Autowired;
75 import org.springframework.stereotype.Component;
76 import fj.data.Either;
77
78 @Component("inputsBusinessLogic")
79 public class InputsBusinessLogic extends BaseBusinessLogic {
80
81     private static final String CREATE_INPUT = "CreateInput";
82     private static final String UPDATE_INPUT = "UpdateInput";
83
84     private static final Logger log = Logger.getLogger(InputsBusinessLogic.class);
85     private static final String FAILED_TO_FOUND_COMPONENT_ERROR = "Failed to found component {}, error: {}";
86     private static final String GET_PROPERTIES_BY_INPUT = "get Properties by input";
87     private static final String FAILED_TO_FOUND_INPUT_UNDER_COMPONENT_ERROR = "Failed to found input {} under component {}, error: {}";
88     private static final String GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP = "Going to execute rollback on create group.";
89     private static final String GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP = "Going to execute commit on create group.";
90
91     private final PropertyDeclarationOrchestrator propertyDeclarationOrchestrator;
92     private final ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
93     private final DataTypeBusinessLogic dataTypeBusinessLogic;
94
95     @Autowired
96     public InputsBusinessLogic(IElementOperation elementDao,
97         IGroupOperation groupOperation,
98         IGroupInstanceOperation groupInstanceOperation,
99         IGroupTypeOperation groupTypeOperation,
100         InterfaceOperation interfaceOperation,
101         InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
102         PropertyDeclarationOrchestrator propertyDeclarationOrchestrator,
103         ComponentInstanceBusinessLogic componentInstanceBusinessLogic, DataTypeBusinessLogic dataTypeBusinessLogic,
104         ArtifactsOperations artifactToscaOperation) {
105         super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation,
106             interfaceOperation, interfaceLifecycleTypeOperation, artifactToscaOperation);
107         this.propertyDeclarationOrchestrator = propertyDeclarationOrchestrator;
108         this.componentInstanceBusinessLogic = componentInstanceBusinessLogic;
109         this.dataTypeBusinessLogic = dataTypeBusinessLogic;
110     }
111
112     /**
113      * associate inputs to a given component with paging
114      *
115      * @param userId
116      * @param componentId
117      * @return
118      */
119     public Either<List<InputDefinition>, ResponseFormat> getInputs(String userId, String componentId) {
120
121         validateUserExists(userId, "get Inputs", false);
122
123         ComponentParametersView filters = new ComponentParametersView();
124         filters.disableAll();
125         filters.setIgnoreInputs(false);
126
127         Either<org.openecomp.sdc.be.model.Component, StorageOperationStatus> getComponentEither = toscaOperationFacade.getToscaElement(componentId, filters);
128         if(getComponentEither.isRight()){
129             ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
130             log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, componentId, actionStatus);
131             return Either.right(componentsUtils.getResponseFormat(actionStatus));
132
133         }
134         org.openecomp.sdc.be.model.Component component = getComponentEither.left().value();
135         List<InputDefinition> inputs = component.getInputs();
136
137         return Either.left(inputs);
138
139     }
140
141     public Either<List<ComponentInstanceInput>, ResponseFormat> getComponentInstanceInputs(String userId, String componentId, String componentInstanceId) {
142
143         validateUserExists(userId, "get Inputs", false);
144         ComponentParametersView filters = new ComponentParametersView();
145         filters.disableAll();
146         filters.setIgnoreInputs(false);
147         filters.setIgnoreComponentInstances(false);
148         filters.setIgnoreComponentInstancesInputs(false);
149
150         Either<org.openecomp.sdc.be.model.Component, StorageOperationStatus> getComponentEither = toscaOperationFacade.getToscaElement(componentId, filters);
151         if(getComponentEither.isRight()){
152             ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
153             log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, componentId, actionStatus);
154             return Either.right(componentsUtils.getResponseFormat(actionStatus));
155
156         }
157         org.openecomp.sdc.be.model.Component component = getComponentEither.left().value();
158
159         if(!ComponentValidations.validateComponentInstanceExist(component, componentInstanceId)){
160             ActionStatus actionStatus = ActionStatus.COMPONENT_INSTANCE_NOT_FOUND;
161             log.debug("Failed to found component instance inputs {}, error: {}", componentInstanceId, actionStatus);
162             return Either.right(componentsUtils.getResponseFormat(actionStatus));
163         }
164                 Map<String, List<ComponentInstanceInput>> ciInputs =
165                                 Optional.ofNullable(component.getComponentInstancesInputs()).orElse(Collections.emptyMap());
166
167                 // Set Constraints on Input
168                 MapUtils.emptyIfNull(ciInputs).values()
169                                 .forEach(inputs -> ListUtils.emptyIfNull(inputs)
170                                                 .forEach(input -> input.setConstraints(setInputConstraint(input))));
171         return Either.left(ciInputs.getOrDefault(componentInstanceId, Collections.emptyList()));
172     }
173
174     /**
175      * associate properties to a given component instance input
176      *
177      * @param instanceId
178      * @param userId
179      * @param inputId
180      * @return
181      */
182
183     public Either<List<ComponentInstanceProperty>, ResponseFormat> getComponentInstancePropertiesByInputId(String userId, String componentId, String instanceId, String inputId) {
184         validateUserExists(userId, GET_PROPERTIES_BY_INPUT, false);
185         String parentId = componentId;
186         org.openecomp.sdc.be.model.Component component;
187         ComponentParametersView filters = new ComponentParametersView();
188         filters.disableAll();
189         filters.setIgnoreComponentInstances(false);
190
191         if(!instanceId.equals(inputId)){
192
193
194             Either<org.openecomp.sdc.be.model.Component, StorageOperationStatus> getComponentEither = toscaOperationFacade.getToscaElement(parentId, filters);
195
196             if(getComponentEither.isRight()){
197                 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
198                 log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, parentId, actionStatus);
199                 return Either.right(componentsUtils.getResponseFormat(actionStatus));
200
201             }
202             component = getComponentEither.left().value();
203             Optional<ComponentInstance> ciOp = component.getComponentInstances().stream().filter(ci ->ci.getUniqueId().equals(instanceId)).findAny();
204             if(ciOp.isPresent()){
205                 parentId = ciOp.get().getComponentUid();
206             }
207
208         }
209
210         filters.setIgnoreInputs(false);
211
212         filters.setIgnoreComponentInstancesProperties(false);
213         filters.setIgnoreComponentInstancesInputs(false);
214         filters.setIgnoreProperties(false);
215
216         Either<org.openecomp.sdc.be.model.Component, StorageOperationStatus> getComponentEither = toscaOperationFacade.getToscaElement(parentId, filters);
217
218         if(getComponentEither.isRight()){
219             ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
220             log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, parentId, actionStatus);
221             return Either.right(componentsUtils.getResponseFormat(actionStatus));
222
223         }
224         component = getComponentEither.left().value();
225
226         Optional<InputDefinition> op = component.getInputs().stream().filter(in -> in.getUniqueId().equals(inputId)).findFirst();
227         if(!op.isPresent()){
228             ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
229             log.debug(FAILED_TO_FOUND_INPUT_UNDER_COMPONENT_ERROR, inputId, parentId, actionStatus);
230             return Either.right(componentsUtils.getResponseFormat(actionStatus));
231         }
232
233         return Either.left(componentInstanceBusinessLogic.getComponentInstancePropertiesByInputId(component, inputId));
234
235     }
236
237     private Either<String,ResponseFormat> updateInputObjectValue(InputDefinition currentInput, InputDefinition newInput, Map<String, DataTypeDefinition> dataTypes) {
238         String innerType = null;
239         String propertyType = currentInput.getType();
240         ToscaPropertyType type = ToscaPropertyType.isValidType(propertyType);
241         log.debug("The type of the property {} is {}", currentInput.getUniqueId(), propertyType);
242
243         if (type == ToscaPropertyType.LIST || type == ToscaPropertyType.MAP) {
244             SchemaDefinition def = currentInput.getSchema();
245             if (def == null) {
246                 log.debug("Schema doesn't exists for property of type {}", type);
247                 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(StorageOperationStatus.INVALID_VALUE)));
248             }
249             PropertyDataDefinition propDef = def.getProperty();
250             if (propDef == null) {
251                 log.debug("Property in Schema Definition inside property of type {} doesn't exist", type);
252                 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(StorageOperationStatus.INVALID_VALUE)));
253             }
254             innerType = propDef.getType();
255         }
256         // Specific Update Logic
257
258         Either<Object, Boolean> isValid = propertyOperation.validateAndUpdatePropertyValue(propertyType, newInput.getDefaultValue(), true, innerType, dataTypes);
259
260         String newValue = currentInput.getDefaultValue();
261         if (isValid.isRight()) {
262             Boolean res = isValid.right().value();
263             if (Boolean.FALSE.equals(res)) {
264                 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(
265                     JanusGraphOperationStatus.ILLEGAL_ARGUMENT))));
266             }
267         } else {
268             Object object = isValid.left().value();
269             if (object != null) {
270                 newValue = object.toString();
271             }
272         }
273         return Either.left(newValue);
274     }
275
276     private InputDefinition getInputFromInputsListById(List<InputDefinition> componentsOldInputs, InputDefinition input) {
277         return componentsOldInputs.stream().filter(in -> in.getUniqueId().equals(input.getUniqueId())).findFirst().orElse(null);
278     }
279
280     public Either<List<InputDefinition>, ResponseFormat> updateInputsValue(ComponentTypeEnum componentType, String componentId, List<InputDefinition> inputs, String userId, boolean shouldLockComp, boolean inTransaction) {
281
282         List<InputDefinition> returnInputs = new ArrayList<>();
283         Either<List<InputDefinition>, ResponseFormat> result = null;
284         org.openecomp.sdc.be.model.Component component = null;
285
286         try {
287             validateUserExists(userId, "get input", false);
288
289             ComponentParametersView componentParametersView = new ComponentParametersView();
290             componentParametersView.disableAll();
291             componentParametersView.setIgnoreInputs(false);
292             componentParametersView.setIgnoreUsers(false);
293                         componentParametersView.setIgnoreProperties(false);
294                         componentParametersView.setIgnoreComponentInstancesProperties(false);
295                         componentParametersView.setIgnoreComponentInstances(false);
296
297             Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(componentId, componentType, componentParametersView);
298
299             if (validateComponent.isRight()) {
300                 result = Either.right(validateComponent.right().value());
301                 return result;
302             }
303             component = validateComponent.left().value();
304
305             if (shouldLockComp) {
306                 Either<Boolean, ResponseFormat> lockComponent = lockComponent(component, UPDATE_INPUT);
307                 if (lockComponent.isRight()) {
308                     result = Either.right(lockComponent.right().value());
309                     return result;
310                 }
311             }
312
313             Either<Boolean, ResponseFormat> canWork = validateCanWorkOnComponent(component, userId);
314             if (canWork.isRight()) {
315                 result = Either.right(canWork.right().value());
316                 return result;
317             }
318
319                         //Validate value and Constraint of input
320                         Either<Boolean, ResponseFormat> constraintValidatorResponse = validateInputValueConstraint(inputs);
321                         if (constraintValidatorResponse.isRight()) {
322                                 log.error("Failed validation value and constraint of property: {}",
323                                                 constraintValidatorResponse.right().value());
324                                 return Either.right(constraintValidatorResponse.right().value());
325                         }
326
327             Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes(applicationDataTypeCache);
328             if (allDataTypes.isRight()) {
329                 result = Either.right(allDataTypes.right().value());
330                 return result;
331             }
332
333             Map<String, DataTypeDefinition> dataTypes = allDataTypes.left().value();
334             List<InputDefinition> componentsOldInputs = Optional.ofNullable(component.getInputs()).orElse(Collections.emptyList());
335             for (InputDefinition newInput: inputs) {
336                 InputDefinition currInput = getInputFromInputsListById(componentsOldInputs, newInput);
337                 if (currInput == null) {
338                     ActionStatus actionStatus = ActionStatus.COMPONENT_NOT_FOUND;
339                     log.debug("Failed to found newInput {} under component {}, error: {}", newInput.getUniqueId(), componentId, actionStatus);
340                     result = Either.right(componentsUtils.getResponseFormat(actionStatus));
341                     return result;
342                 }
343                 Either<String, ResponseFormat> updateInputObjectValue = updateInputObjectValue(currInput, newInput, dataTypes);
344                 if ( updateInputObjectValue.isRight()) {
345                     return Either.right(updateInputObjectValue.right().value());
346                 }
347                 String newValue = updateInputObjectValue.left().value();
348                 currInput.setValue(newValue);
349                 currInput.setDefaultValue(newValue);
350                 currInput.setOwnerId(userId);
351                 Either<InputDefinition, StorageOperationStatus> status = toscaOperationFacade.updateInputOfComponent(component, currInput);
352                 if(status.isRight()){
353                     ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(status.right().value());
354                     result = Either.right(componentsUtils.getResponseFormat(actionStatus, ""));
355                     return result;
356                 } else {
357                     returnInputs.add(status.left().value());
358                 }
359             }
360             result = Either.left(returnInputs);
361             return result;
362         } finally {
363                 if (!inTransaction) {
364                     if (result == null || result.isRight()) {
365                         log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP);
366                         janusGraphDao.rollback();
367                     } else {
368                         log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP);
369                         janusGraphDao.commit();
370                     }
371                 }
372                 // unlock resource
373                 if (shouldLockComp && component != null) {
374                     graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
375                 }
376             }
377     }
378
379     private Either<Boolean, ResponseFormat> validateInputValueConstraint(List<InputDefinition> inputs) {
380                 PropertyValueConstraintValidationUtil propertyValueConstraintValidationUtil =
381                                 PropertyValueConstraintValidationUtil.getInstance();
382                 List<InputDefinition> inputDefinitions = new ArrayList<>();
383                 for (InputDefinition inputDefinition : inputs) {
384                         InputDefinition inputDef = new InputDefinition();
385                         inputDefinition.setDefaultValue(inputDefinition.getDefaultValue());
386                         inputDefinition.setInputPath(inputDefinition.getSubPropertyInputPath());
387                         inputDefinition.setType(inputDefinition.getType());
388                         if (Objects.nonNull(inputDefinition.getParentPropertyType())) {
389                                 ComponentInstanceProperty propertyDefinition = new ComponentInstanceProperty();
390                                 propertyDefinition.setType(inputDefinition.getParentPropertyType());
391
392                                 inputDefinition.setProperties(Collections.singletonList(propertyDefinition));
393                         }
394
395                         inputDefinitions.add(inputDef);
396                 }
397
398                 return propertyValueConstraintValidationUtil.validatePropertyConstraints(inputDefinitions, applicationDataTypeCache);
399         }
400
401     public Either<List<ComponentInstanceInput>, ResponseFormat> getInputsForComponentInput(String userId, String componentId, String inputId) {
402         validateUserExists(userId, GET_PROPERTIES_BY_INPUT, false);
403         org.openecomp.sdc.be.model.Component component = null;
404         ComponentParametersView filters = new ComponentParametersView();
405         filters.disableAll();
406         filters.setIgnoreComponentInstances(false);
407         filters.setIgnoreInputs(false);
408         filters.setIgnoreComponentInstancesInputs(false);
409         filters.setIgnoreProperties(false);
410
411         Either<org.openecomp.sdc.be.model.Component, StorageOperationStatus> getComponentEither = toscaOperationFacade.getToscaElement(componentId, filters);
412
413         if(getComponentEither.isRight()){
414             ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
415             log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, componentId, actionStatus);
416             return Either.right(componentsUtils.getResponseFormat(actionStatus));
417
418         }
419         component = getComponentEither.left().value();
420
421         Optional<InputDefinition> op = component.getInputs().stream().filter(in -> in.getUniqueId().equals(inputId)).findFirst();
422         if(!op.isPresent()){
423             ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
424             log.debug(FAILED_TO_FOUND_INPUT_UNDER_COMPONENT_ERROR, inputId, componentId, actionStatus);
425             return Either.right(componentsUtils.getResponseFormat(actionStatus));
426         }
427
428         return Either.left(componentInstanceBusinessLogic.getComponentInstanceInputsByInputId(component, inputId));
429
430     }
431
432     @Override
433     public Either<List<InputDefinition>, ResponseFormat> declareProperties(String userId, String componentId,
434             ComponentTypeEnum componentTypeEnum, ComponentInstInputsMap componentInstInputsMap) {
435
436         return createMultipleInputs(userId, componentId, componentTypeEnum, componentInstInputsMap, true, false);
437     }
438
439     public Either<List<InputDefinition>, ResponseFormat> createMultipleInputs(String userId, String componentId, ComponentTypeEnum componentType, ComponentInstInputsMap componentInstInputsMapUi, boolean shouldLockComp, boolean inTransaction) {
440
441         Either<List<InputDefinition>, ResponseFormat> result = null;
442         org.openecomp.sdc.be.model.Component component = null;
443
444         try {
445             validateUserExists(userId, GET_PROPERTIES_BY_INPUT, false);
446
447             component = getAndValidateComponentForCreate(userId, componentId, componentType, shouldLockComp);
448
449             result =  propertyDeclarationOrchestrator.declarePropertiesToInputs(component, componentInstInputsMapUi)
450                     .left()
451                     .bind(inputsToCreate -> prepareInputsForCreation(userId, componentId, inputsToCreate))
452                     .right()
453                                         .map(componentsUtils::getResponseFormat);
454
455             return result;
456
457         } catch (ByResponseFormatComponentException e) {
458             log.error("#createMultipleInputs: Exception thrown: ", e);
459             result = Either.right(e.getResponseFormat());
460             return result;
461         } finally {
462
463             if (!inTransaction) {
464                 if (result == null || result.isRight()) {
465                     log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP);
466                     janusGraphDao.rollback();
467                 } else {
468                     log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP);
469                     janusGraphDao.commit();
470                 }
471             }
472             // unlock resource
473             if (shouldLockComp && component != null) {
474                 graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
475             }
476
477         }
478     }
479
480     /**
481      * Creates a list input with a data type which has properties specified.
482      *
483      * @param userId User ID
484      * @param componentId Component ID
485      * @param componentType Component type
486      * @param componentListInput Properties to be declared and input to be created
487      * @param shouldLockComp true if the component should be locked
488      * @param inTransaction true if already in transaction
489      */
490     public Either<List<InputDefinition>, ResponseFormat> createListInput(String userId, String componentId,
491         ComponentTypeEnum componentType, ComponentInstListInput componentListInput, boolean shouldLockComp,
492         boolean inTransaction) {
493
494         Either<List<InputDefinition>, ResponseFormat> result = null;
495         org.openecomp.sdc.be.model.Component component = null;
496
497         log.trace("#createListInput: enter");
498
499         try {
500             /* check if user exists */
501             validateUserExists(userId, GET_PROPERTIES_BY_INPUT, false);
502
503             component = getAndValidateComponentForCreate(userId, componentId, componentType, shouldLockComp);
504
505             InputDefinition listInput = componentListInput.getListInput();
506             DataTypeDefinition dataType =
507                 prepareDataTypeForListInput(componentListInput.getComponentInstInputsMap(), listInput);
508             Map<String, DataTypeDefinition> dataTypesMap = new HashMap<>();
509             dataTypesMap.put(dataType.getName(), dataType);
510             if (log.isDebugEnabled()) {
511                 log.debug("#createListInput: dataTypesMap={}", ReflectionToStringBuilder.toString(dataTypesMap));
512             }
513
514             Either<List<DataTypeDefinition>, StorageOperationStatus> dataTypeResult =
515                 toscaOperationFacade.addDataTypesToComponent(dataTypesMap, componentId);
516             if (dataTypeResult.isRight()) {
517                 log.debug("#createListInput: DataType creation failed.");
518                 throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(dataTypeResult.right().value()));
519             }
520
521             // create list input
522             listInput.setUniqueId(UniqueIdBuilder.buildPropertyUniqueId(componentId, listInput.getName()));
523             listInput.setInstanceUniqueId(
524                 propertyDeclarationOrchestrator.getPropOwnerId(componentListInput.getComponentInstInputsMap()));
525             listInput.setIsDeclaredListInput(true);
526             Map<String, InputDefinition> listInputMap = new HashMap<>();
527             listInputMap.put(listInput.getName(), listInput);
528             result = createListInputsInGraph(listInputMap, dataTypesMap, component);
529             if (result.isRight()) {
530                 log.debug("#createListInput: createListInputsInGraph failed.");
531                 throw new ByResponseFormatComponentException(result.right().value());
532             }
533
534             // update properties
535             result = propertyDeclarationOrchestrator
536                 .declarePropertiesToListInput(component, componentListInput.getComponentInstInputsMap(), listInput)
537                 .right().map(err -> componentsUtils.getResponseFormat(err))
538                 .left().map(Arrays::asList);
539
540             log.trace("#createListInput: leave");
541
542             return result;
543
544         } catch (ByResponseFormatComponentException e) {
545             log.error("#createListInput: Exception thrown", e);
546             result = Either.right(e.getResponseFormat());
547             return result;
548         } finally {
549
550             if (!inTransaction) {
551                 if (result == null || result.isRight()) {
552                     log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP);
553                     janusGraphDao.rollback();
554                 } else {
555                     log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP);
556                     janusGraphDao.commit();
557                 }
558             }
559             // unlock resource
560             if (shouldLockComp && component != null) {
561                 graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
562             }
563         }
564     }
565
566     private ComponentParametersView getBaseComponentParametersView() {
567         ComponentParametersView componentParametersView = new ComponentParametersView();
568         componentParametersView.disableAll();
569         componentParametersView.setIgnoreInputs(false);
570         componentParametersView.setIgnoreComponentInstances(false);
571         componentParametersView.setIgnoreComponentInstancesInputs(false);
572         componentParametersView.setIgnoreComponentInstancesProperties(false);
573         componentParametersView.setIgnorePolicies(false);
574         componentParametersView.setIgnoreGroups(false);
575         componentParametersView.setIgnoreUsers(false);
576         return componentParametersView;
577     }
578
579     private org.openecomp.sdc.be.model.Component getAndValidateComponentForCreate(
580         String userId, String componentId, ComponentTypeEnum componentType, boolean shouldLockComp
581     ) {
582
583         ComponentParametersView componentParametersView = getBaseComponentParametersView();
584
585         Either<org.openecomp.sdc.be.model.Component, ResponseFormat> componentEither =
586             // get Component Object
587             validateComponentExists(componentId, componentType, componentParametersView)
588             .left().bind(component -> {
589                 if (shouldLockComp) {
590                     // lock the component
591                     return lockComponent(component, CREATE_INPUT).left().map(result -> component);
592                 }
593                 return Either.left(component);
594             }).left().bind(component -> validateCanWorkOnComponent(component, userId).left().map(result -> component));
595         if (componentEither.isRight()) {
596             throw new ByResponseFormatComponentException(componentEither.right().value());
597         }
598         return componentEither.left().value();
599     }
600
601     private DataTypeDefinition prepareDataTypeForListInput(ComponentInstInputsMap inputsMap, InputDefinition input) {
602         // Confirm if type is list
603         if (StringUtils.isEmpty(input.getType()) || !input.getType().equals(ToscaPropertyType.LIST.getType())) {
604             log.debug("#prepareDataTypeForListInput: Type of input is not list.");
605             throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_TYPE));
606         }
607
608         // Confirm schema type is not empty
609         String desiredTypeName = input.getSchemaType();
610         if (StringUtils.isEmpty(desiredTypeName)) {
611             log.debug("#prepareDataTypeForListInput: Schema type of list input is empty.");
612             throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_INNER_TYPE));
613         }
614
615         DataTypeDefinition dataType = new DataTypeDefinition();
616         List<ComponentInstancePropInput> propInputs = inputsMap.resolvePropertiesToDeclare().getRight();
617         dataType.setName(desiredTypeName);
618         dataType.setDerivedFromName(ToscaPropertyType.Root.getType());
619         // Copy properties from inputsMap
620         dataType.setProperties(propInputs.stream().map(PropertyDefinition::new).collect(Collectors.toList()));
621         return dataType;
622     }
623
624     private  Either<List<InputDefinition>, StorageOperationStatus> prepareInputsForCreation(String userId, String cmptId, List<InputDefinition> inputsToCreate) {
625         Map<String, InputDefinition> inputsToPersist = MapUtil.toMap(inputsToCreate, InputDefinition::getName);
626         assignOwnerIdToInputs(userId, inputsToPersist);
627                 inputsToPersist.values()
628                                 .forEach(input -> input.setConstraints(componentInstanceBusinessLogic.setInputConstraint(input)));
629
630         return toscaOperationFacade.addInputsToComponent(inputsToPersist, cmptId)
631                 .left()
632                 .map(persistedInputs -> inputsToCreate);
633     }
634
635     private void assignOwnerIdToInputs(String userId, Map<String, InputDefinition> inputsToCreate) {
636         inputsToCreate.values().forEach(inputDefinition -> inputDefinition.setOwnerId(userId));
637     }
638
639     public Either<List<InputDefinition>, ResponseFormat> createInputsInGraph(Map<String, InputDefinition> inputs, org.openecomp.sdc.be.model.Component component) {
640
641         List<InputDefinition> resourceProperties = component.getInputs();
642         Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes(applicationDataTypeCache);
643         if (allDataTypes.isRight()) {
644             return Either.right(allDataTypes.right().value());
645         }
646
647         Map<String, DataTypeDefinition> dataTypes = allDataTypes.left().value();
648
649         for (Map.Entry<String, InputDefinition> inputDefinition : inputs.entrySet()) {
650             String inputName = inputDefinition.getKey();
651             inputDefinition.getValue().setName(inputName);
652
653             Either<InputDefinition, ResponseFormat> preparedInputEither = prepareAndValidateInputBeforeCreate(inputDefinition.getValue(), dataTypes);
654             if(preparedInputEither.isRight()){
655                 return Either.right(preparedInputEither.right().value());
656             }
657
658         }
659         if (resourceProperties != null) {
660             Map<String, InputDefinition> generatedInputs = resourceProperties.stream().collect(Collectors.toMap(PropertyDataDefinition::getName, i -> i));
661             Either<Map<String, InputDefinition>, String> mergeEither = ToscaDataDefinition.mergeDataMaps(generatedInputs, inputs);
662             if(mergeEither.isRight()){
663                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_ALREADY_EXIST, mergeEither.right().value()));
664             }
665             inputs = mergeEither.left().value();
666         }
667
668         Either<List<InputDefinition>, StorageOperationStatus> associateInputsEither = toscaOperationFacade.createAndAssociateInputs(inputs, component.getUniqueId());
669         if(associateInputsEither.isRight()){
670             log.debug("Failed to create inputs under component {}. Status is {}", component.getUniqueId(), associateInputsEither.right().value());
671             return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(associateInputsEither.right().value())));
672         }
673         return Either.left(associateInputsEither.left().value());
674     }
675
676     private Either<List<InputDefinition>, ResponseFormat> createListInputsInGraph(Map<String, InputDefinition> inputs,
677         Map<String, DataTypeDefinition> privateDataTypes, org.openecomp.sdc.be.model.Component component) {
678
679         log.trace("#createListInputsInGraph: enter");
680         Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes(
681             applicationDataTypeCache);
682         if (allDataTypes.isRight()) {
683             return Either.right(allDataTypes.right().value());
684         }
685
686         Map<String, DataTypeDefinition> dataTypes = allDataTypes.left().value();
687         dataTypes.putAll(privateDataTypes);
688
689         for (Map.Entry<String, InputDefinition> inputDefinition : inputs.entrySet()) {
690             String inputName = inputDefinition.getKey();
691             inputDefinition.getValue().setName(inputName);
692
693             Either<InputDefinition, ResponseFormat> preparedInputEither =
694                 prepareAndValidateInputBeforeCreate(inputDefinition.getValue(), dataTypes);
695             if (preparedInputEither.isRight()) {
696                 return Either.right(preparedInputEither.right().value());
697             }
698         }
699
700         Either<List<InputDefinition>, StorageOperationStatus> addInputsEither = toscaOperationFacade
701             .addInputsToComponent(inputs, component.getUniqueId());
702         if (addInputsEither.isRight()) {
703             log.debug("#createListInputsInGraph: Failed to create inputs under component {}. Status is {}",
704                 component.getUniqueId(), addInputsEither.right().value());
705             return Either.right(componentsUtils.getResponseFormat(
706                 componentsUtils.convertFromStorageResponse(addInputsEither.right().value())));
707         }
708         log.trace("#createListInputsInGraph: leave");
709         return Either.left(addInputsEither.left().value());
710     }
711
712     /**
713      * Delete input from service
714      *
715      * @param componentId
716      * @param userId
717      * @param inputId
718      * @return
719      */
720     public Either<InputDefinition, ResponseFormat> deleteInput(String componentId, String userId, String inputId) {
721
722         Either<InputDefinition, ResponseFormat> deleteEither = null;
723         if (log.isDebugEnabled()) {
724             log.debug("Going to delete input id: {}", inputId);
725         }
726
727         validateUserExists(userId, "Delete input", true);
728
729         ComponentParametersView componentParametersView = getBaseComponentParametersView();
730         componentParametersView.setIgnoreInterfaces(false);
731         componentParametersView.setIgnoreDataType(false);
732         componentParametersView.setIgnoreProperties(false);
733
734         Either<org.openecomp.sdc.be.model.Component, StorageOperationStatus> componentEither =
735             toscaOperationFacade.getToscaElement(componentId, componentParametersView);
736         if (componentEither.isRight()) {
737             deleteEither = Either.right(componentsUtils.getResponseFormat(
738                 componentsUtils.convertFromStorageResponse(componentEither.right().value())));
739             return deleteEither;
740         }
741         org.openecomp.sdc.be.model.Component component = componentEither.left().value();
742
743         // Validate inputId is child of the component
744         Optional<InputDefinition> optionalInput = component.getInputs().stream().
745                 // filter by ID
746                         filter(input -> input.getUniqueId().equals(inputId)).
747                 // Get the input
748                         findAny();
749         if (!optionalInput.isPresent()) {
750             return Either.right(
751                 componentsUtils.getResponseFormat(ActionStatus.INPUT_IS_NOT_CHILD_OF_COMPONENT, inputId, componentId));
752         }
753
754         InputDefinition inputForDelete = optionalInput.get();
755
756         // Lock component
757         Either<Boolean, ResponseFormat> lockResultEither =
758             lockComponent(componentId, component, "deleteInput");
759         if (lockResultEither.isRight()) {
760             ResponseFormat responseFormat = lockResultEither.right().value();
761             deleteEither = Either.right(responseFormat);
762             return deleteEither;
763         }
764
765         // Delete input operations
766         try {
767             StorageOperationStatus status =
768                 toscaOperationFacade.deleteInputOfResource(component, inputForDelete.getName());
769             if (status != StorageOperationStatus.OK) {
770                 log.debug("Component id: {} delete input id: {} failed", componentId, inputId);
771                 deleteEither = Either.right(componentsUtils.getResponseFormat(
772                     componentsUtils.convertFromStorageResponse(status), component.getName()));
773                 return deleteEither;
774             }
775
776             if (BooleanUtils.isTrue(inputForDelete.getIsDeclaredListInput())){
777                 deleteEither = deleteListInput(componentId, inputId, component, inputForDelete, status);
778                 return deleteEither;
779             }
780
781             StorageOperationStatus storageOperationStatus =
782                 propertyDeclarationOrchestrator.unDeclarePropertiesAsInputs(component, inputForDelete);
783             if (storageOperationStatus != StorageOperationStatus.OK) {
784                 log.debug("Component id: {} update properties declared as input for input id: {} failed", componentId, inputId);
785                 deleteEither = Either.right(componentsUtils.getResponseFormat(
786                     componentsUtils.convertFromStorageResponse(status), component.getName()));
787                 return deleteEither;
788             }
789
790             deleteEither = Either.left(inputForDelete);
791             return deleteEither;
792         } finally {
793             if (deleteEither == null || deleteEither.isRight()) {
794                 log.debug("Component id: {} delete input id: {} failed", componentId, inputId);
795                 janusGraphDao.rollback();
796             } else {
797                 log.debug("Component id: {} delete input id: {} success", componentId, inputId);
798                 janusGraphDao.commit();
799             }
800             unlockComponent(deleteEither, component);
801         }
802     }
803
804     private Either<InputDefinition, ResponseFormat> deleteListInput(String componentId, String inputId,
805         org.openecomp.sdc.be.model.Component component,
806         InputDefinition inputForDelete, StorageOperationStatus status) {
807         // the input is created by 'Declare List'.
808         // need to 1. undeclare properties, 2. delete input, 3. delete private data type
809
810         StorageOperationStatus storageOperationStatus =
811             propertyDeclarationOrchestrator.unDeclarePropertiesAsListInputs(component, inputForDelete);
812         if (storageOperationStatus != StorageOperationStatus.OK) {
813             log.debug("Component id: {} update properties declared as input for input id: {} failed", componentId, inputId);
814             return Either.right(componentsUtils.getResponseFormat(
815                 componentsUtils.convertFromStorageResponse(status), component.getName()));
816         }
817         Either<DataTypeDefinition, StorageOperationStatus> deleteResult =
818             dataTypeBusinessLogic.deletePrivateDataType(component, inputForDelete.getSchemaType());
819         if (deleteResult.isRight()) {
820             log.debug("Component id: {} delete datatype name: {} failed", componentId, inputForDelete.getSchemaType());
821             return Either.right(componentsUtils.getResponseFormat(
822                 componentsUtils.convertFromStorageResponse(deleteResult.right().value()), component.getName()));
823         }
824         log.trace("deleteInput: deletePrivateDataType (OK)");
825         return Either.left(inputForDelete);
826     }
827
828     private Either<InputDefinition, ResponseFormat> prepareAndValidateInputBeforeCreate(InputDefinition newInputDefinition, Map<String, DataTypeDefinition> dataTypes) {
829
830         // validate input default values
831         Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newInputDefinition, dataTypes);
832         if (defaultValuesValidation.isRight()) {
833             return Either.right(defaultValuesValidation.right().value());
834         }
835         // convert property
836         ToscaPropertyType type = getType(newInputDefinition.getType());
837         if (type != null && newInputDefinition != null) {
838             PropertyValueConverter converter = type.getConverter();
839             // get inner type
840             SchemaDefinition schema = newInputDefinition.getSchema();
841             String innerType = null;
842             if (schema != null) {
843                 PropertyDataDefinition prop = schema.getProperty();
844                 if (prop != null) {
845                     innerType = prop.getType();
846                 }
847             }
848             String convertedValue;
849             if (newInputDefinition.getDefaultValue() != null) {
850                 convertedValue = converter.convert(newInputDefinition.getDefaultValue(), innerType, dataTypes);
851                 newInputDefinition.setDefaultValue(convertedValue);
852             }
853         }
854         return Either.left(newInputDefinition);
855     }
856
857     public Either<InputDefinition, ResponseFormat> getInputsAndPropertiesForComponentInput(String userId, String componentId, String inputId, boolean inTransaction) {
858         Either<InputDefinition, ResponseFormat> result = null;
859         try {
860
861             validateUserExists(userId, GET_PROPERTIES_BY_INPUT, false);
862             ComponentParametersView filters = new ComponentParametersView();
863             filters.disableAll();
864             filters.setIgnoreComponentInstances(false);
865             filters.setIgnoreInputs(false);
866             filters.setIgnoreComponentInstancesInputs(false);
867             filters.setIgnoreComponentInstancesProperties(false);
868             filters.setIgnoreProperties(false);
869             Either<org.openecomp.sdc.be.model.Component, StorageOperationStatus> getComponentEither = toscaOperationFacade.getToscaElement(componentId, filters);
870             if(getComponentEither.isRight()){
871                 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
872                 log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, componentId, actionStatus);
873                 return Either.right(componentsUtils.getResponseFormat(actionStatus));
874
875             }
876             org.openecomp.sdc.be.model.Component component = getComponentEither.left().value();
877             Optional<InputDefinition> op = component.getInputs().stream().filter(in -> in.getUniqueId().equals(inputId)).findFirst();
878             if(!op.isPresent()){
879                 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
880                 log.debug(FAILED_TO_FOUND_INPUT_UNDER_COMPONENT_ERROR, inputId, componentId, actionStatus);
881                 return Either.right(componentsUtils.getResponseFormat(actionStatus));
882             }
883
884             InputDefinition resObj = op.get();
885
886             List<ComponentInstanceInput> inputCIInput = componentInstanceBusinessLogic.getComponentInstanceInputsByInputId(component, inputId) ;
887
888             resObj.setInputs(inputCIInput);
889
890
891             List<ComponentInstanceProperty> inputProps = componentInstanceBusinessLogic.getComponentInstancePropertiesByInputId(component, inputId) ;
892
893             resObj.setProperties(inputProps);
894
895
896             result = Either.left(resObj);
897
898             return result;
899
900         } finally {
901
902             if (!inTransaction) {
903
904                 if (result == null || result.isRight()) {
905                     log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP);
906                     janusGraphDao.rollback();
907                 } else {
908                     log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP);
909                     janusGraphDao.commit();
910                 }
911
912             }
913
914         }
915
916     }
917
918 }