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