2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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 * ================================================================================
22 package org.openecomp.sdc.be.components.impl;
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;
31 import java.util.Objects;
32 import java.util.Optional;
33 import java.util.concurrent.atomic.AtomicReference;
34 import java.util.stream.Collectors;
35 import org.apache.commons.collections.CollectionUtils;
36 import org.apache.commons.collections4.ListUtils;
37 import org.apache.commons.collections4.MapUtils;
38 import org.apache.commons.lang3.BooleanUtils;
39 import org.apache.commons.lang3.StringUtils;
40 import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
41 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
42 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
43 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
44 import org.openecomp.sdc.be.components.property.PropertyDeclarationOrchestrator;
45 import org.openecomp.sdc.be.components.validation.ComponentValidations;
46 import org.openecomp.sdc.be.config.BeEcompErrorManager;
47 import org.openecomp.sdc.be.dao.api.ActionStatus;
48 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
49 import org.openecomp.sdc.be.dao.utils.MapUtil;
50 import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil;
51 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
52 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
53 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
54 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
55 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
56 import org.openecomp.sdc.be.model.Component;
57 import org.openecomp.sdc.be.model.ComponentInstInputsMap;
58 import org.openecomp.sdc.be.model.ComponentInstListInput;
59 import org.openecomp.sdc.be.model.ComponentInstance;
60 import org.openecomp.sdc.be.model.ComponentInstanceInput;
61 import org.openecomp.sdc.be.model.ComponentInstancePropInput;
62 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
63 import org.openecomp.sdc.be.model.ComponentParametersView;
64 import org.openecomp.sdc.be.model.DataTypeDefinition;
65 import org.openecomp.sdc.be.model.InputDefinition;
66 import org.openecomp.sdc.be.model.PropertyDefinition;
67 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
68 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
69 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
70 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
71 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
72 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
73 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
74 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
75 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
76 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
77 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
78 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
79 import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
80 import org.openecomp.sdc.be.resources.data.EntryData;
81 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
82 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
83 import org.openecomp.sdc.common.log.enums.StatusCode;
84 import org.openecomp.sdc.common.log.wrappers.Logger;
85 import org.openecomp.sdc.exception.ResponseFormat;
86 import org.springframework.beans.factory.annotation.Autowired;
88 @org.springframework.stereotype.Component("inputsBusinessLogic")
89 public class InputsBusinessLogic extends BaseBusinessLogic {
91 private static final String CREATE_INPUT = "CreateInput";
92 private static final String UPDATE_INPUT = "UpdateInput";
93 private static final Logger log = Logger.getLogger(InputsBusinessLogic.class);
94 private static final String FAILED_TO_FOUND_COMPONENT_ERROR = "Failed to found component {}, error: {}";
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;
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;
120 * associate inputs to a given component with paging
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<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));
138 Component component = getComponentEither.left().value();
139 List<InputDefinition> inputs = component.getInputs();
140 return Either.left(inputs);
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<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));
158 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));
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()));
175 * associate properties to a given component instance input
182 public Either<List<ComponentInstanceProperty>, ResponseFormat> getComponentInstancePropertiesByInputId(String userId, String componentId,
183 String instanceId, String inputId) {
184 validateUserExists(userId);
185 String parentId = componentId;
187 ComponentParametersView filters = new ComponentParametersView();
188 filters.disableAll();
189 filters.setIgnoreComponentInstances(false);
190 if (!instanceId.equals(inputId)) {
191 Either<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));
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();
204 filters.setIgnoreInputs(false);
205 filters.setIgnoreComponentInstancesProperties(false);
206 filters.setIgnoreComponentInstancesInputs(false);
207 filters.setIgnoreProperties(false);
208 Either<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));
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));
222 return Either.left(componentInstanceBusinessLogic.getComponentInstancePropertiesByInputId(component, inputId));
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();
233 log.debug("Schema doesn't exists for property of type {}", type);
234 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(StorageOperationStatus.INVALID_VALUE));
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));
241 innerType = propDef.getType();
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)));
254 Object object = isValid.left().value();
255 if (object != null) {
256 newValue = object.toString();
262 private InputDefinition getInputFromInputsListById(List<InputDefinition> componentsOldInputs, InputDefinition input) {
263 return componentsOldInputs.stream().filter(in -> in.getUniqueId().equals(input.getUniqueId())).findFirst().orElse(null);
266 public Either<List<InputDefinition>, ResponseFormat> updateInputsValue(ComponentTypeEnum componentType, String componentId,
267 List<InputDefinition> inputs, String userId, boolean shouldLockComp) {
268 List<InputDefinition> returnInputs = new ArrayList<>();
269 Either<List<InputDefinition>, ResponseFormat> result = null;
270 Component component = null;
272 validateUserExists(userId);
273 ComponentParametersView componentParametersView = new ComponentParametersView();
274 componentParametersView.disableAll();
275 componentParametersView.setIgnoreInputs(false);
276 componentParametersView.setIgnoreUsers(false);
277 componentParametersView.setIgnoreProperties(false);
278 componentParametersView.setIgnoreComponentInstancesProperties(false);
279 componentParametersView.setIgnoreComponentInstances(false);
280 component = validateComponentExists(componentId, componentType, componentParametersView);
281 if (shouldLockComp) {
283 lockComponent(component, UPDATE_INPUT);
284 } catch (ComponentException e) {
285 log.error("Failed to lock component", e);
286 result = Either.right(e.getResponseFormat());
290 //Validate value and Constraint of input
291 Either<Boolean, ResponseFormat> constraintValidatorResponse = validateInputValueConstraint(inputs, component.getModel());
292 if (constraintValidatorResponse.isRight()) {
293 log.error("Failed validation value and constraint of property: {}", constraintValidatorResponse.right().value());
294 unlockComponent(true, component);
295 return Either.right(constraintValidatorResponse.right().value());
297 validateCanWorkOnComponent(component, userId);
298 Map<String, DataTypeDefinition> dataTypes;
299 dataTypes = componentsUtils.getAllDataTypes(applicationDataTypeCache, component.getModel());
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 unlockComponent(true, component);
307 return Either.right(componentsUtils.getResponseFormat(actionStatus));
309 String updateInputObjectValue = updateInputObjectValue(currInput, newInput, dataTypes);
310 currInput.setDefaultValue(updateInputObjectValue);
311 currInput.setOwnerId(userId);
312 currInput.setMetadata(newInput.getMetadata());
313 if (newInput.getConstraints() != null) {
314 currInput.setConstraints(newInput.getConstraints());
316 if (newInput.isRequired() != null) {
317 currInput.setRequired(newInput.isRequired());
319 Either<InputDefinition, StorageOperationStatus> status = toscaOperationFacade.updateInputOfComponent(component, currInput);
320 if (status.isRight()) {
321 ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(status.right().value());
322 unlockComponent(true, component);
323 return Either.right(componentsUtils.getResponseFormat(actionStatus, ""));
325 returnInputs.add(status.left().value());
328 result = Either.left(returnInputs);
329 } catch (ComponentException e) {
330 log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_UPDATE_INPUT);
331 unlockRollbackWithException(component, e);
332 } catch (Exception e) {
333 log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_UPDATE_INPUT);
334 unlockRollbackWithException(component, new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR));
336 log.debug(GOING_TO_EXECUTE_COMMIT_ON_UPDATE_INPUT);
337 unlockWithCommit(component);
341 private Either<Boolean, ResponseFormat> validateInputValueConstraint(List<InputDefinition> inputs, final String model) {
342 PropertyValueConstraintValidationUtil propertyValueConstraintValidationUtil = new PropertyValueConstraintValidationUtil();
343 List<InputDefinition> inputDefinitions = new ArrayList<>();
344 for (InputDefinition inputDefinition : inputs) {
345 InputDefinition inputDef = new InputDefinition();
346 inputDef.setName(inputDefinition.getName());
347 inputDef.setDefaultValue(inputDefinition.getDefaultValue());
348 inputDef.setInputPath(inputDefinition.getSubPropertyInputPath());
349 inputDef.setType(inputDefinition.getType());
350 inputDef.setConstraints(inputDefinition.getConstraints());
351 if (Objects.nonNull(inputDefinition.getParentPropertyType())) {
352 ComponentInstanceProperty propertyDefinition = new ComponentInstanceProperty();
353 propertyDefinition.setType(inputDefinition.getParentPropertyType());
354 inputDef.setProperties(Collections.singletonList(propertyDefinition));
356 inputDefinitions.add(inputDef);
358 return propertyValueConstraintValidationUtil.validatePropertyConstraints(inputDefinitions, applicationDataTypeCache, model);
361 public Either<List<ComponentInstanceInput>, ResponseFormat> getInputsForComponentInput(String userId, String componentId, String inputId) {
362 validateUserExists(userId);
363 Component component = null;
364 ComponentParametersView filters = new ComponentParametersView();
365 filters.disableAll();
366 filters.setIgnoreComponentInstances(false);
367 filters.setIgnoreInputs(false);
368 filters.setIgnoreComponentInstancesInputs(false);
369 filters.setIgnoreProperties(false);
370 Either<Component, StorageOperationStatus> getComponentEither = toscaOperationFacade
371 .getToscaElement(componentId, filters);
372 if (getComponentEither.isRight()) {
373 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
374 log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, componentId, actionStatus);
375 return Either.right(componentsUtils.getResponseFormat(actionStatus));
377 component = getComponentEither.left().value();
378 Optional<InputDefinition> op = component.getInputs().stream().filter(in -> in.getUniqueId().equals(inputId)).findFirst();
379 if (!op.isPresent()) {
380 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
381 log.debug(FAILED_TO_FOUND_INPUT_UNDER_COMPONENT_ERROR, inputId, componentId, actionStatus);
382 return Either.right(componentsUtils.getResponseFormat(actionStatus));
384 return Either.left(componentInstanceBusinessLogic.getComponentInstanceInputsByInputId(component, inputId));
388 public Either<List<InputDefinition>, ResponseFormat> declareProperties(String userId, String componentId, ComponentTypeEnum componentTypeEnum,
389 ComponentInstInputsMap componentInstInputsMap) {
390 return createMultipleInputs(userId, componentId, componentTypeEnum, componentInstInputsMap, true, false);
393 private Either<List<InputDefinition>, ResponseFormat> createMultipleInputs(String userId, String componentId, ComponentTypeEnum componentType,
394 ComponentInstInputsMap componentInstInputsMapUi,
395 boolean shouldLockComp,
396 boolean inTransaction) {
397 Either<List<InputDefinition>, ResponseFormat> result = null;
398 Component component = null;
400 validateUserExists(userId);
401 component = getAndValidateComponentForCreate(userId, componentId, componentType, shouldLockComp);
402 StorageOperationStatus status = validateInputName(component, componentInstInputsMapUi);
403 if (status != StorageOperationStatus.OK) {
404 log.debug("Input name already exist");
405 throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.INPUT_NAME_ALREADY_EXIST));
407 result = propertyDeclarationOrchestrator.declarePropertiesToInputs(component, componentInstInputsMapUi).left()
408 .bind(inputsToCreate -> prepareInputsForCreation(userId, componentId, inputsToCreate)).right()
409 .map(componentsUtils::getResponseFormat);
411 } catch (ByResponseFormatComponentException e) {
412 log.error("#createMultipleInputs: Exception thrown: ", e);
413 result = Either.right(e.getResponseFormat());
416 if (!inTransaction) {
417 if (result == null || result.isRight()) {
418 log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP);
419 janusGraphDao.rollback();
421 log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP);
422 janusGraphDao.commit();
426 if (shouldLockComp && component != null) {
427 graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
432 private StorageOperationStatus validateInputName(final Component component, final ComponentInstInputsMap componentInstInputsMap) {
433 AtomicReference<StorageOperationStatus> storageOperationStatus = new AtomicReference<>(StorageOperationStatus.OK);
434 Map<String, List<ComponentInstancePropInput>> inputDeclaredProperties = new HashMap<>();
435 if (MapUtils.isNotEmpty(componentInstInputsMap.getComponentInstanceProperties())) {
436 inputDeclaredProperties = componentInstInputsMap.getComponentInstanceProperties();
437 } else if (MapUtils.isNotEmpty(componentInstInputsMap.getServiceProperties())) {
438 inputDeclaredProperties = componentInstInputsMap.getServiceProperties();
441 if (MapUtils.isNotEmpty(inputDeclaredProperties) && CollectionUtils.isNotEmpty(component.getInputs())) {
442 inputDeclaredProperties.values()
443 .forEach(componentInstancePropInputs ->
444 componentInstancePropInputs
445 .forEach(componentInstancePropInput -> component.getInputs()
446 .forEach(existingInput -> {
447 if (existingInput.getName().equals(componentInstancePropInput.getInputName())) {
448 storageOperationStatus.set(StorageOperationStatus.INVALID_VALUE);
454 return storageOperationStatus.get();
458 * Creates a list input with a data type which has properties specified.
460 * @param userId User ID
461 * @param componentId Component ID
462 * @param componentType Component type
463 * @param componentListInput Properties to be declared and input to be created
464 * @param shouldLockComp true if the component should be locked
465 * @param inTransaction true if already in transaction
467 public Either<List<InputDefinition>, ResponseFormat> createListInput(String userId, String componentId, ComponentTypeEnum componentType,
468 ComponentInstListInput componentListInput, boolean shouldLockComp,
469 boolean inTransaction) {
470 Either<List<InputDefinition>, ResponseFormat> result = null;
471 Component component = null;
472 log.trace("#createListInput: enter");
474 /* check if user exists */
475 validateUserExists(userId);
477 component = getAndValidateComponentForCreate(userId, componentId, componentType, shouldLockComp);
479 InputDefinition listInput = componentListInput.getListInput();
480 DataTypeDefinition dataType =
481 prepareDataTypeForListInput(componentListInput.getComponentInstInputsMap(), listInput);
482 Map<String, DataTypeDefinition> dataTypesMap = new HashMap<>();
483 dataTypesMap.put(dataType.getName(), dataType);
484 if (log.isDebugEnabled()) {
485 log.debug("#createListInput: dataTypesMap={}", ReflectionToStringBuilder.toString(dataTypesMap));
488 Either<List<DataTypeDefinition>, StorageOperationStatus> dataTypeResult =
489 toscaOperationFacade.addDataTypesToComponent(dataTypesMap, componentId);
490 if (dataTypeResult.isRight()) {
491 log.debug("#createListInput: DataType creation failed.");
492 throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(dataTypeResult.right().value()));
496 listInput.setUniqueId(UniqueIdBuilder.buildPropertyUniqueId(componentId, listInput.getName()));
497 listInput.setInstanceUniqueId(
498 propertyDeclarationOrchestrator.getPropOwnerId(componentListInput.getComponentInstInputsMap()));
499 listInput.setIsDeclaredListInput(true);
500 Map<String, InputDefinition> listInputMap = new HashMap<>();
501 listInputMap.put(listInput.getName(), listInput);
502 result = createListInputsInGraph(listInputMap, dataTypesMap, component);
503 if (result.isRight()) {
504 log.debug("#createListInput: createListInputsInGraph failed.");
505 throw new ByResponseFormatComponentException(result.right().value());
509 result = propertyDeclarationOrchestrator
510 .declarePropertiesToListInput(component, componentListInput.getComponentInstInputsMap(), listInput)
511 .right().map(err -> componentsUtils.getResponseFormat(err))
512 .left().map(Arrays::asList);
514 log.trace("#createListInput: leave");
518 } catch (ByResponseFormatComponentException e) {
519 log.error("#createListInput: Exception thrown", e);
520 result = Either.right(e.getResponseFormat());
524 if (!inTransaction) {
525 if (result == null || result.isRight()) {
526 log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP);
527 janusGraphDao.rollback();
529 log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP);
530 janusGraphDao.commit();
534 if (shouldLockComp && component != null) {
535 graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
540 private ComponentParametersView getBaseComponentParametersView() {
541 ComponentParametersView componentParametersView = new ComponentParametersView();
542 componentParametersView.disableAll();
543 componentParametersView.setIgnoreInputs(false);
544 componentParametersView.setIgnoreComponentInstances(false);
545 componentParametersView.setIgnoreComponentInstancesInputs(false);
546 componentParametersView.setIgnoreComponentInstancesProperties(false);
547 componentParametersView.setIgnorePolicies(false);
548 componentParametersView.setIgnoreGroups(false);
549 componentParametersView.setIgnoreUsers(false);
550 return componentParametersView;
553 private Component getAndValidateComponentForCreate(
554 String userId, String componentId, ComponentTypeEnum componentType, boolean shouldLockComp
556 ComponentParametersView componentParametersView = getBaseComponentParametersView();
557 Component component = validateComponentExists(componentId, componentType, componentParametersView);
558 if (shouldLockComp) {
559 // lock the component
560 lockComponent(component, CREATE_INPUT);
562 validateCanWorkOnComponent(component, userId);
566 private DataTypeDefinition prepareDataTypeForListInput(ComponentInstInputsMap inputsMap, InputDefinition input) {
567 // Confirm if type is list
568 if (StringUtils.isEmpty(input.getType()) || !input.getType().equals(ToscaPropertyType.LIST.getType())) {
569 log.debug("#prepareDataTypeForListInput: Type of input is not list.");
570 throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_TYPE));
573 // Confirm schema type is not empty
574 String desiredTypeName = input.getSchemaType();
575 if (StringUtils.isEmpty(desiredTypeName)) {
576 log.debug("#prepareDataTypeForListInput: Schema type of list input is empty.");
577 throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_INNER_TYPE));
580 DataTypeDefinition dataType = new DataTypeDefinition();
581 List<ComponentInstancePropInput> propInputs = inputsMap.resolvePropertiesToDeclare().getRight();
582 dataType.setName(desiredTypeName);
583 dataType.setDerivedFromName(ToscaPropertyType.ROOT.getType());
584 // Copy properties from inputsMap
585 dataType.setProperties(propInputs.stream().map(PropertyDefinition::new).collect(Collectors.toList()));
589 private Either<List<InputDefinition>, StorageOperationStatus> prepareInputsForCreation(String userId, String cmptId,
590 List<InputDefinition> inputsToCreate) {
591 Map<String, InputDefinition> inputsToPersist = MapUtil.toMap(inputsToCreate, InputDefinition::getName);
592 assignOwnerIdToInputs(userId, inputsToPersist);
593 inputsToPersist.values()
594 .forEach(input -> input.setConstraints(componentInstanceBusinessLogic.setInputConstraint(input)));
596 return toscaOperationFacade.addInputsToComponent(inputsToPersist, cmptId)
598 .map(persistedInputs -> inputsToCreate);
601 private void assignOwnerIdToInputs(String userId, Map<String, InputDefinition> inputsToCreate) {
602 inputsToCreate.values().forEach(inputDefinition -> inputDefinition.setOwnerId(userId));
605 public Either<List<InputDefinition>, ResponseFormat> createInputsInGraph(Map<String, InputDefinition> inputs,
606 Component component) {
608 List<InputDefinition> resourceProperties = component.getInputs();
610 final Map<String, DataTypeDefinition> dataTypes = componentsUtils.getAllDataTypes(applicationDataTypeCache, component.getModel());
612 for (Map.Entry<String, InputDefinition> inputDefinition : inputs.entrySet()) {
613 String inputName = inputDefinition.getKey();
614 inputDefinition.getValue().setName(inputName);
616 Either<InputDefinition, ResponseFormat> preparedInputEither = prepareAndValidateInputBeforeCreate(inputDefinition.getValue(), dataTypes);
617 if (preparedInputEither.isRight()) {
618 return Either.right(preparedInputEither.right().value());
622 if (resourceProperties != null) {
623 Map<String, InputDefinition> generatedInputs = resourceProperties.stream()
624 .collect(Collectors.toMap(PropertyDataDefinition::getName, i -> i));
625 Either<Map<String, InputDefinition>, String> mergeEither = ToscaDataDefinition.mergeDataMaps(generatedInputs, inputs);
626 if (mergeEither.isRight()) {
627 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_ALREADY_EXIST, mergeEither.right().value()));
629 inputs = mergeEither.left().value();
632 Either<List<InputDefinition>, StorageOperationStatus> associateInputsEither = toscaOperationFacade
633 .createAndAssociateInputs(inputs, component.getUniqueId());
634 if (associateInputsEither.isRight()) {
635 log.debug("Failed to create inputs under component {}. Status is {}", component.getUniqueId(), associateInputsEither.right().value());
637 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(associateInputsEither.right().value())));
639 return Either.left(associateInputsEither.left().value());
642 private Either<List<InputDefinition>, ResponseFormat> createListInputsInGraph(Map<String, InputDefinition> inputs,
643 Map<String, DataTypeDefinition> privateDataTypes,
644 Component component) {
646 log.trace("#createListInputsInGraph: enter");
648 Map<String, DataTypeDefinition> dataTypes = componentsUtils.getAllDataTypes(applicationDataTypeCache, component.getModel());
649 dataTypes.putAll(privateDataTypes);
651 for (Map.Entry<String, InputDefinition> inputDefinition : inputs.entrySet()) {
652 String inputName = inputDefinition.getKey();
653 inputDefinition.getValue().setName(inputName);
655 Either<InputDefinition, ResponseFormat> preparedInputEither =
656 prepareAndValidateInputBeforeCreate(inputDefinition.getValue(), dataTypes);
657 if (preparedInputEither.isRight()) {
658 return Either.right(preparedInputEither.right().value());
662 Either<List<InputDefinition>, StorageOperationStatus> addInputsEither = toscaOperationFacade
663 .addInputsToComponent(inputs, component.getUniqueId());
664 if (addInputsEither.isRight()) {
665 log.debug("#createListInputsInGraph: Failed to create inputs under component {}. Status is {}",
666 component.getUniqueId(), addInputsEither.right().value());
667 return Either.right(componentsUtils.getResponseFormat(
668 componentsUtils.convertFromStorageResponse(addInputsEither.right().value())));
670 log.trace("#createListInputsInGraph: leave");
671 return Either.left(addInputsEither.left().value());
675 * Delete input from service
682 public InputDefinition deleteInput(String componentId, String userId, String inputId) {
683 Either<InputDefinition, ResponseFormat> deleteEither = null;
684 if (log.isDebugEnabled()) {
685 log.debug("Going to delete input id: {}", inputId);
687 validateUserExists(userId);
688 ComponentParametersView componentParametersView = getBaseComponentParametersView();
689 componentParametersView.setIgnoreInterfaces(false);
690 componentParametersView.setIgnoreDataType(false);
691 componentParametersView.setIgnoreProperties(false);
692 Either<Component, StorageOperationStatus> componentEither = toscaOperationFacade
693 .getToscaElement(componentId, componentParametersView);
694 if (componentEither.isRight()) {
695 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(componentEither.right().value()));
697 Component component = componentEither.left().value();
698 // Validate inputId is child of the component
699 Optional<InputDefinition> optionalInput = component.getInputs().stream().
701 filter(input -> input.getUniqueId().equals(inputId)).
704 if (!optionalInput.isPresent()) {
705 throw new ByActionStatusComponentException(ActionStatus.INPUT_IS_NOT_CHILD_OF_COMPONENT, inputId, componentId);
707 InputDefinition inputForDelete = optionalInput.get();
709 lockComponent(componentId, component, "deleteInput");
710 // Delete input operations
711 boolean failed = false;
713 StorageOperationStatus status = toscaOperationFacade.deleteInputOfResource(component, inputForDelete.getName());
714 if (status != StorageOperationStatus.OK) {
715 log.debug("Component id: {} delete input id: {} failed", componentId, inputId);
716 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(status), component.getName());
718 if (BooleanUtils.isTrue(inputForDelete.getIsDeclaredListInput())) {
719 deleteEither = deleteListInput(componentId, inputId, component, inputForDelete, status);
720 if (deleteEither.isRight()) {
721 throw new ByResponseFormatComponentException(deleteEither.right().value());
723 return deleteEither.left().value();
725 StorageOperationStatus storageOperationStatus = propertyDeclarationOrchestrator.unDeclarePropertiesAsInputs(component, inputForDelete);
726 if (storageOperationStatus != StorageOperationStatus.OK) {
727 log.debug("Component id: {} update properties declared as input for input id: {} failed", componentId, inputId);
728 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(storageOperationStatus), component.getName());
730 return inputForDelete;
731 } catch (ComponentException e) {
735 unlockComponent(failed, component);
739 private Either<InputDefinition, ResponseFormat> deleteListInput(String componentId, String inputId,
740 Component component, InputDefinition inputForDelete,
741 StorageOperationStatus status) {
742 // the input is created by 'Declare List'.
743 // need to 1. undeclare properties, 2. delete input, 3. delete private data type
744 StorageOperationStatus storageOperationStatus = propertyDeclarationOrchestrator.unDeclarePropertiesAsListInputs(component, inputForDelete);
745 if (storageOperationStatus != StorageOperationStatus.OK) {
746 log.debug("Component id: {} update properties declared as input for input id: {} failed", componentId, inputId);
747 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status), component.getName()));
749 Either<DataTypeDefinition, StorageOperationStatus> deleteResult = dataTypeBusinessLogic
750 .deletePrivateDataType(component, inputForDelete.getSchemaType());
751 if (deleteResult.isRight()) {
752 log.debug("Component id: {} delete datatype name: {} failed", componentId, inputForDelete.getSchemaType());
754 componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(deleteResult.right().value()), component.getName()));
756 log.trace("deleteInput: deletePrivateDataType (OK)");
757 return Either.left(inputForDelete);
760 private Either<InputDefinition, ResponseFormat> prepareAndValidateInputBeforeCreate(InputDefinition newInputDefinition,
761 Map<String, DataTypeDefinition> dataTypes) {
762 // validate input default values
763 Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newInputDefinition, dataTypes);
764 if (defaultValuesValidation.isRight()) {
765 return Either.right(defaultValuesValidation.right().value());
768 ToscaPropertyType type = getType(newInputDefinition.getType());
770 PropertyValueConverter converter = type.getConverter();
772 SchemaDefinition schema = newInputDefinition.getSchema();
773 String innerType = null;
774 if (schema != null) {
775 PropertyDataDefinition prop = schema.getProperty();
777 innerType = prop.getType();
780 String convertedValue;
781 if (newInputDefinition.getDefaultValue() != null) {
782 convertedValue = converter.convert(newInputDefinition.getDefaultValue(), innerType, dataTypes);
783 newInputDefinition.setDefaultValue(convertedValue);
786 return Either.left(newInputDefinition);
789 public Either<InputDefinition, ResponseFormat> getInputsAndPropertiesForComponentInput(String userId, String componentId, String inputId,
790 boolean inTransaction) {
791 Either<InputDefinition, ResponseFormat> result = null;
793 validateUserExists(userId);
794 ComponentParametersView filters = new ComponentParametersView();
795 filters.disableAll();
796 filters.setIgnoreComponentInstances(false);
797 filters.setIgnoreInputs(false);
798 filters.setIgnoreComponentInstancesInputs(false);
799 filters.setIgnoreComponentInstancesProperties(false);
800 filters.setIgnoreProperties(false);
801 Either<Component, StorageOperationStatus> getComponentEither = toscaOperationFacade
802 .getToscaElement(componentId, filters);
803 if (getComponentEither.isRight()) {
804 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
805 log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, componentId, actionStatus);
806 return Either.right(componentsUtils.getResponseFormat(actionStatus));
808 Component component = getComponentEither.left().value();
809 Optional<InputDefinition> op = component.getInputs().stream().filter(in -> in.getUniqueId().equals(inputId)).findFirst();
810 if (!op.isPresent()) {
811 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
812 log.debug(FAILED_TO_FOUND_INPUT_UNDER_COMPONENT_ERROR, inputId, componentId, actionStatus);
813 return Either.right(componentsUtils.getResponseFormat(actionStatus));
815 InputDefinition resObj = op.get();
816 List<ComponentInstanceInput> inputCIInput = componentInstanceBusinessLogic.getComponentInstanceInputsByInputId(component, inputId);
817 resObj.setInputs(inputCIInput);
818 List<ComponentInstanceProperty> inputProps = componentInstanceBusinessLogic.getComponentInstancePropertiesByInputId(component, inputId);
819 resObj.setProperties(inputProps);
820 result = Either.left(resObj);
823 if (!inTransaction) {
824 if (result == null || result.isRight()) {
825 log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP);
826 janusGraphDao.rollback();
828 log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP);
829 janusGraphDao.commit();
835 public Either<EntryData<String, InputDefinition>, ResponseFormat> addInputToComponent(String componentId, String inputName,
836 InputDefinition newInputDefinition, String userId) {
837 Either<EntryData<String, InputDefinition>, ResponseFormat> result = null;
838 validateUserExists(userId);
839 Either<Component, StorageOperationStatus> serviceElement = toscaOperationFacade.getToscaElement(componentId);
840 if (serviceElement.isRight()) {
841 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
844 Component component = serviceElement.left().value();
845 NodeTypeEnum nodeType = component.getComponentType().getNodeType();
846 StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, nodeType);
847 if (!lockResult.equals(StorageOperationStatus.OK)) {
848 BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_INPUT, nodeType.name().toLowerCase(), componentId);
849 log.info("Failed to lock component {}. Error - {}", componentId, lockResult);
850 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
854 if (!ComponentValidationUtils.canWorkOnComponent(component, userId)) {
855 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
858 List<InputDefinition> inputs = component.getInputs();
859 if (CollectionUtils.isEmpty(inputs)) {
860 inputs = new ArrayList<>();
862 if (isInputExistInComponent(inputs, inputName)) {
863 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INPUT_ALREADY_EXIST, inputName));
866 Map<String, DataTypeDefinition> allDataTypes = componentsUtils.getAllDataTypes(applicationDataTypeCache, component.getModel());
867 // validate input default values
868 Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newInputDefinition, allDataTypes);
869 if (defaultValuesValidation.isRight()) {
870 result = Either.right(defaultValuesValidation.right().value());
874 ToscaPropertyType type = getType(newInputDefinition.getType());
876 PropertyValueConverter converter = type.getConverter();
878 String innerType = null;
879 SchemaDefinition schema = newInputDefinition.getSchema();
880 if (schema != null) {
881 PropertyDataDefinition prop = schema.getProperty();
883 innerType = prop.getType();
886 if (newInputDefinition.getDefaultValue() != null) {
887 String convertedValue = converter.convert(newInputDefinition.getDefaultValue(), innerType, allDataTypes);
888 newInputDefinition.setDefaultValue(convertedValue);
891 newInputDefinition.setMappedToComponentProperty(false);
892 Either<InputDefinition, StorageOperationStatus> addInputEither = toscaOperationFacade
893 .addInputToComponent(inputName, newInputDefinition, component);
894 if (addInputEither.isRight()) {
895 log.info("Failed to add new input {}. Error - {}", componentId, addInputEither.right().value());
896 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
899 result = Either.left(new EntryData<>(inputName, newInputDefinition));
902 commitOrRollback(result);
904 graphLockOperation.unlockComponent(componentId, nodeType);
908 private boolean isInputExistInComponent(List<InputDefinition> inputs, String inputName) {
909 return CollectionUtils.isNotEmpty(inputs) && inputs.stream().anyMatch(input -> input.getName().equals(inputName));