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