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