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