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