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.apache.commons.lang3.tuple.ImmutablePair;
42 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
43 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
44 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
45 import org.openecomp.sdc.be.components.property.PropertyDeclarationOrchestrator;
46 import org.openecomp.sdc.be.components.validation.ComponentValidations;
47 import org.openecomp.sdc.be.config.BeEcompErrorManager;
48 import org.openecomp.sdc.be.dao.api.ActionStatus;
49 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
50 import org.openecomp.sdc.be.dao.utils.MapUtil;
51 import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil;
52 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
53 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
54 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
55 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
56 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
57 import org.openecomp.sdc.be.model.Component;
58 import org.openecomp.sdc.be.model.ComponentInstInputsMap;
59 import org.openecomp.sdc.be.model.ComponentInstListInput;
60 import org.openecomp.sdc.be.model.ComponentInstance;
61 import org.openecomp.sdc.be.model.ComponentInstanceInput;
62 import org.openecomp.sdc.be.model.ComponentInstancePropInput;
63 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
64 import org.openecomp.sdc.be.model.ComponentParametersView;
65 import org.openecomp.sdc.be.model.DataTypeDefinition;
66 import org.openecomp.sdc.be.model.InputDefinition;
67 import org.openecomp.sdc.be.model.PropertyDefinition;
68 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
69 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
70 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
71 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
72 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
73 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
74 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
75 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
76 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
77 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
78 import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils;
79 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
80 import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
81 import org.openecomp.sdc.be.resources.data.EntryData;
82 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
83 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
84 import org.openecomp.sdc.common.log.enums.StatusCode;
85 import org.openecomp.sdc.common.log.wrappers.Logger;
86 import org.openecomp.sdc.exception.ResponseFormat;
87 import org.springframework.beans.factory.annotation.Autowired;
89 @org.springframework.stereotype.Component("inputsBusinessLogic")
90 public class InputsBusinessLogic extends BaseBusinessLogic {
92 private static final String CREATE_INPUT = "CreateInput";
93 private static final String UPDATE_INPUT = "UpdateInput";
94 private static final Logger log = Logger.getLogger(InputsBusinessLogic.class);
95 private static final String FAILED_TO_FOUND_COMPONENT_ERROR = "Failed to found component {}, error: {}";
96 private static final String FAILED_TO_FOUND_INPUT_UNDER_COMPONENT_ERROR = "Failed to found input {} under component {}, error: {}";
97 private static final String GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP = "Going to execute rollback on create group.";
98 private static final String GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP = "Going to execute commit on create group.";
99 private static final String GOING_TO_EXECUTE_ROLLBACK_ON_UPDATE_INPUT = "Going to execute rollback on update input.";
100 private static final String GOING_TO_EXECUTE_COMMIT_ON_UPDATE_INPUT = "Going to execute commit on update input.";
101 private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(InputsBusinessLogic.class.getName());
102 private final PropertyDeclarationOrchestrator propertyDeclarationOrchestrator;
103 private final ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
104 private final DataTypeBusinessLogic dataTypeBusinessLogic;
107 public InputsBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation, IGroupInstanceOperation groupInstanceOperation,
108 IGroupTypeOperation groupTypeOperation, InterfaceOperation interfaceOperation,
109 InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
110 PropertyDeclarationOrchestrator propertyDeclarationOrchestrator,
111 ComponentInstanceBusinessLogic componentInstanceBusinessLogic, DataTypeBusinessLogic dataTypeBusinessLogic,
112 ArtifactsOperations artifactToscaOperation) {
113 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
114 artifactToscaOperation);
115 this.propertyDeclarationOrchestrator = propertyDeclarationOrchestrator;
116 this.componentInstanceBusinessLogic = componentInstanceBusinessLogic;
117 this.dataTypeBusinessLogic = dataTypeBusinessLogic;
121 * associate inputs to a given component with paging
127 public Either<List<InputDefinition>, ResponseFormat> getInputs(String userId, String componentId) {
128 validateUserExists(userId);
129 ComponentParametersView filters = new ComponentParametersView();
130 filters.disableAll();
131 filters.setIgnoreInputs(false);
132 Either<Component, StorageOperationStatus> getComponentEither = toscaOperationFacade
133 .getToscaElement(componentId, filters);
134 if (getComponentEither.isRight()) {
135 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
136 log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, componentId, actionStatus);
137 return Either.right(componentsUtils.getResponseFormat(actionStatus));
139 Component component = getComponentEither.left().value();
140 List<InputDefinition> inputs = component.getInputs();
141 return Either.left(inputs);
144 public Either<List<ComponentInstanceInput>, ResponseFormat> getComponentInstanceInputs(String userId, String componentId,
145 String componentInstanceId) {
146 validateUserExists(userId);
147 ComponentParametersView filters = new ComponentParametersView();
148 filters.disableAll();
149 filters.setIgnoreInputs(false);
150 filters.setIgnoreComponentInstances(false);
151 filters.setIgnoreComponentInstancesInputs(false);
152 Either<Component, StorageOperationStatus> getComponentEither = toscaOperationFacade
153 .getToscaElement(componentId, filters);
154 if (getComponentEither.isRight()) {
155 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
156 log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, componentId, actionStatus);
157 return Either.right(componentsUtils.getResponseFormat(actionStatus));
159 Component component = getComponentEither.left().value();
160 if (!ComponentValidations.validateComponentInstanceExist(component, componentInstanceId)) {
161 ActionStatus actionStatus = ActionStatus.COMPONENT_INSTANCE_NOT_FOUND;
162 log.debug("Failed to found component instance inputs {}, error: {}", componentInstanceId, actionStatus);
163 loggerSupportability.log(LoggerSupportabilityActions.CREATE_INPUTS, component.getComponentMetadataForSupportLog(), StatusCode.ERROR,
164 "Failed to found component instance inputs componentInstanceId: {}", componentInstanceId);
165 return Either.right(componentsUtils.getResponseFormat(actionStatus));
167 Map<String, List<ComponentInstanceInput>> ciInputs = Optional.ofNullable(component.getComponentInstancesInputs())
168 .orElse(Collections.emptyMap());
169 // Set Constraints on Input
170 MapUtils.emptyIfNull(ciInputs).values()
171 .forEach(inputs -> ListUtils.emptyIfNull(inputs).forEach(input -> input.setConstraints(setInputConstraint(input))));
172 return Either.left(ciInputs.getOrDefault(componentInstanceId, Collections.emptyList()));
176 * associate properties to a given component instance input
183 public Either<List<ComponentInstanceProperty>, ResponseFormat> getComponentInstancePropertiesByInputId(String userId, String componentId,
184 String instanceId, String inputId) {
185 validateUserExists(userId);
186 String parentId = componentId;
188 ComponentParametersView filters = new ComponentParametersView();
189 filters.disableAll();
190 filters.setIgnoreComponentInstances(false);
191 if (!instanceId.equals(inputId)) {
192 Either<Component, StorageOperationStatus> getComponentEither = toscaOperationFacade
193 .getToscaElement(parentId, filters);
194 if (getComponentEither.isRight()) {
195 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
196 log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, parentId, actionStatus);
197 return Either.right(componentsUtils.getResponseFormat(actionStatus));
199 component = getComponentEither.left().value();
200 Optional<ComponentInstance> ciOp = component.getComponentInstances().stream().filter(ci -> ci.getUniqueId().equals(instanceId)).findAny();
201 if (ciOp.isPresent()) {
202 parentId = ciOp.get().getComponentUid();
205 filters.setIgnoreInputs(false);
206 filters.setIgnoreComponentInstancesProperties(false);
207 filters.setIgnoreComponentInstancesInputs(false);
208 filters.setIgnoreProperties(false);
209 Either<Component, StorageOperationStatus> getComponentEither = toscaOperationFacade
210 .getToscaElement(parentId, filters);
211 if (getComponentEither.isRight()) {
212 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
213 log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, parentId, actionStatus);
214 return Either.right(componentsUtils.getResponseFormat(actionStatus));
216 component = getComponentEither.left().value();
217 Optional<InputDefinition> op = component.getInputs().stream().filter(in -> in.getUniqueId().equals(inputId)).findFirst();
218 if (!op.isPresent()) {
219 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
220 log.debug(FAILED_TO_FOUND_INPUT_UNDER_COMPONENT_ERROR, inputId, parentId, actionStatus);
221 return Either.right(componentsUtils.getResponseFormat(actionStatus));
223 return Either.left(componentInstanceBusinessLogic.getComponentInstancePropertiesByInputId(component, inputId));
226 private String updateInputObjectValue(InputDefinition currentInput, InputDefinition newInput, Map<String, DataTypeDefinition> dataTypes) {
227 String innerType = null;
228 String propertyType = currentInput.getType();
229 ToscaPropertyType type = ToscaPropertyType.isValidType(propertyType);
230 log.debug("The type of the property {} is {}", currentInput.getUniqueId(), propertyType);
231 if (type == ToscaPropertyType.LIST || type == ToscaPropertyType.MAP) {
232 SchemaDefinition def = currentInput.getSchema();
234 log.debug("Schema doesn't exists for property of type {}", type);
235 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(StorageOperationStatus.INVALID_VALUE));
237 PropertyDataDefinition propDef = def.getProperty();
238 if (propDef == null) {
239 log.debug("Property in Schema Definition inside property of type {} doesn't exist", type);
240 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(StorageOperationStatus.INVALID_VALUE));
242 innerType = propDef.getType();
244 // Specific Update Logic
245 Either<Object, Boolean> isValid = propertyOperation
246 .validateAndUpdatePropertyValue(propertyType, newInput.getDefaultValue(), true, innerType, dataTypes);
247 String newValue = newInput.getDefaultValue();
248 if (isValid.isRight()) {
249 Boolean res = isValid.right().value();
250 if (Boolean.FALSE.equals(res)) {
251 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(
252 DaoStatusConverter.convertJanusGraphStatusToStorageStatus(JanusGraphOperationStatus.ILLEGAL_ARGUMENT)));
255 Object object = isValid.left().value();
256 if (object != null) {
257 newValue = object.toString();
263 private InputDefinition getInputFromInputsListById(List<InputDefinition> componentsOldInputs, InputDefinition input) {
264 return componentsOldInputs.stream().filter(in -> in.getUniqueId().equals(input.getUniqueId())).findFirst().orElse(null);
267 public Either<List<InputDefinition>, ResponseFormat> updateInputsValue(ComponentTypeEnum componentType, String componentId,
268 List<InputDefinition> inputs, String userId, boolean shouldLockComp) {
269 List<InputDefinition> returnInputs = new ArrayList<>();
270 Either<List<InputDefinition>, ResponseFormat> result = null;
271 Component component = null;
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) {
284 lockComponent(component, UPDATE_INPUT);
285 } catch (ComponentException e) {
286 log.error("Failed to lock component", e);
287 result = Either.right(e.getResponseFormat());
291 //Validate value and Constraint of input
292 Either<Boolean, ResponseFormat> constraintValidatorResponse = validateInputValueConstraint(inputs, component.getModel());
293 if (constraintValidatorResponse.isRight()) {
294 log.error("Failed validation value and constraint of property: {}", constraintValidatorResponse.right().value());
295 unlockComponent(true, component);
296 return Either.right(constraintValidatorResponse.right().value());
298 validateCanWorkOnComponent(component, userId);
299 Map<String, DataTypeDefinition> dataTypes;
300 dataTypes = componentsUtils.getAllDataTypes(applicationDataTypeCache, component.getModel());
301 List<InputDefinition> componentsOldInputs = Optional.ofNullable(component.getInputs()).orElse(Collections.emptyList());
302 for (InputDefinition newInput : inputs) {
303 InputDefinition currInput = getInputFromInputsListById(componentsOldInputs, newInput);
304 if (currInput == null) {
305 ActionStatus actionStatus = ActionStatus.COMPONENT_NOT_FOUND;
306 log.debug("Failed to found newInput {} under component {}, error: {}", newInput.getUniqueId(), componentId, actionStatus);
307 unlockComponent(true, component);
308 return Either.right(componentsUtils.getResponseFormat(actionStatus));
310 String updateInputObjectValue = updateInputObjectValue(currInput, newInput, dataTypes);
311 currInput.setDefaultValue(updateInputObjectValue);
312 currInput.setOwnerId(userId);
313 currInput.setMetadata(newInput.getMetadata());
314 if (newInput.getConstraints() != null) {
315 currInput.setConstraints(newInput.getConstraints());
317 if (newInput.isRequired() != null) {
318 currInput.setRequired(newInput.isRequired());
320 Either<InputDefinition, StorageOperationStatus> status = toscaOperationFacade.updateInputOfComponent(component, currInput);
321 if (status.isRight()) {
322 ActionStatus actionStatus = componentsUtils.convertFromStorageResponseForResourceInstanceProperty(status.right().value());
323 unlockComponent(true, component);
324 return Either.right(componentsUtils.getResponseFormat(actionStatus, ""));
326 returnInputs.add(status.left().value());
329 result = Either.left(returnInputs);
330 } catch (ComponentException e) {
331 log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_UPDATE_INPUT);
332 unlockRollbackWithException(component, e);
333 } catch (Exception e) {
334 log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_UPDATE_INPUT);
335 unlockRollbackWithException(component, new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR));
337 log.debug(GOING_TO_EXECUTE_COMMIT_ON_UPDATE_INPUT);
338 unlockWithCommit(component);
342 private Either<Boolean, ResponseFormat> validateInputValueConstraint(List<InputDefinition> inputs, final String model) {
343 PropertyValueConstraintValidationUtil propertyValueConstraintValidationUtil = new PropertyValueConstraintValidationUtil();
344 List<InputDefinition> inputDefinitions = new ArrayList<>();
345 for (InputDefinition inputDefinition : inputs) {
346 InputDefinition inputDef = new InputDefinition();
347 inputDef.setName(inputDefinition.getName());
348 inputDef.setDefaultValue(inputDefinition.getDefaultValue());
349 inputDef.setInputPath(inputDefinition.getSubPropertyInputPath());
350 inputDef.setType(inputDefinition.getType());
351 inputDef.setConstraints(inputDefinition.getConstraints());
352 if (Objects.nonNull(inputDefinition.getParentPropertyType())) {
353 ComponentInstanceProperty propertyDefinition = new ComponentInstanceProperty();
354 propertyDefinition.setType(inputDefinition.getParentPropertyType());
355 inputDef.setProperties(Collections.singletonList(propertyDefinition));
357 inputDefinitions.add(inputDef);
359 return propertyValueConstraintValidationUtil.validatePropertyConstraints(inputDefinitions, applicationDataTypeCache, model);
362 public Either<List<ComponentInstanceInput>, ResponseFormat> getInputsForComponentInput(String userId, String componentId, String inputId) {
363 validateUserExists(userId);
364 Component component = null;
365 ComponentParametersView filters = new ComponentParametersView();
366 filters.disableAll();
367 filters.setIgnoreComponentInstances(false);
368 filters.setIgnoreInputs(false);
369 filters.setIgnoreComponentInstancesInputs(false);
370 filters.setIgnoreProperties(false);
371 Either<Component, StorageOperationStatus> getComponentEither = toscaOperationFacade
372 .getToscaElement(componentId, filters);
373 if (getComponentEither.isRight()) {
374 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
375 log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, componentId, actionStatus);
376 return Either.right(componentsUtils.getResponseFormat(actionStatus));
378 component = getComponentEither.left().value();
379 Optional<InputDefinition> op = component.getInputs().stream().filter(in -> in.getUniqueId().equals(inputId)).findFirst();
380 if (!op.isPresent()) {
381 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
382 log.debug(FAILED_TO_FOUND_INPUT_UNDER_COMPONENT_ERROR, inputId, componentId, actionStatus);
383 return Either.right(componentsUtils.getResponseFormat(actionStatus));
385 return Either.left(componentInstanceBusinessLogic.getComponentInstanceInputsByInputId(component, inputId));
389 public Either<List<InputDefinition>, ResponseFormat> declareProperties(String userId, String componentId, ComponentTypeEnum componentTypeEnum,
390 ComponentInstInputsMap componentInstInputsMap) {
391 return createMultipleInputs(userId, componentId, componentTypeEnum, componentInstInputsMap, true, false);
394 private Either<List<InputDefinition>, ResponseFormat> createMultipleInputs(String userId, String componentId, ComponentTypeEnum componentType,
395 ComponentInstInputsMap componentInstInputsMapUi,
396 boolean shouldLockComp,
397 boolean inTransaction) {
398 Either<List<InputDefinition>, ResponseFormat> result = null;
399 Component component = null;
401 validateUserExists(userId);
402 component = getAndValidateComponentForCreate(userId, componentId, componentType, shouldLockComp);
403 ImmutablePair<StorageOperationStatus, String> status = validateInputName(component, componentInstInputsMapUi);
404 if (status.getLeft() != StorageOperationStatus.OK) {
405 log.debug("Input name already exist");
406 throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.INPUT_NAME_ALREADY_EXIST, status.getRight()));
408 result = propertyDeclarationOrchestrator.declarePropertiesToInputs(component, componentInstInputsMapUi).left()
409 .bind(inputsToCreate -> prepareInputsForCreation(userId, componentId, inputsToCreate)).right()
410 .map(componentsUtils::getResponseFormat);
412 } catch (ByResponseFormatComponentException e) {
413 log.error("#createMultipleInputs: Exception thrown: ", e);
414 result = Either.right(e.getResponseFormat());
417 if (!inTransaction) {
418 if (result == null || result.isRight()) {
419 log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP);
420 janusGraphDao.rollback();
422 log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP);
423 janusGraphDao.commit();
427 if (shouldLockComp && component != null) {
428 graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
433 private ImmutablePair<StorageOperationStatus, String> validateInputName(final Component component,
434 final ComponentInstInputsMap componentInstInputsMap) {
435 final Map<String, List<ComponentInstancePropInput>> inputDeclaredProperties = new HashMap<>();
436 if (MapUtils.isNotEmpty(componentInstInputsMap.getComponentInstanceProperties())) {
437 inputDeclaredProperties.putAll(componentInstInputsMap.getComponentInstanceProperties());
438 } else if (MapUtils.isNotEmpty(componentInstInputsMap.getServiceProperties())) {
439 inputDeclaredProperties.putAll(componentInstInputsMap.getServiceProperties());
441 if (MapUtils.isNotEmpty(inputDeclaredProperties) && CollectionUtils.isNotEmpty(component.getInputs())) {
442 for (final List<ComponentInstancePropInput> componentInstancePropInputs : inputDeclaredProperties.values()) {
443 for (final ComponentInstancePropInput componentInstancePropInput : componentInstancePropInputs) {
444 final Optional<InputDefinition> inputDefinition = component.getInputs().stream()
445 .filter(input -> input.getName().equals(componentInstancePropInput.getInputName())
446 || input.getName().equals(componentInstancePropInput.getName())).findAny();
447 if (inputDefinition.isPresent()) {
448 return new ImmutablePair<>(StorageOperationStatus.INVALID_VALUE, inputDefinition.get().getName());
453 return new ImmutablePair<>(StorageOperationStatus.OK, StringUtils.EMPTY);
457 * Creates a list input with a data type which has properties specified.
459 * @param userId User ID
460 * @param componentId Component ID
461 * @param componentType Component type
462 * @param componentListInput Properties to be declared and input to be created
463 * @param shouldLockComp true if the component should be locked
464 * @param inTransaction true if already in transaction
466 public Either<List<InputDefinition>, ResponseFormat> createListInput(String userId, String componentId, ComponentTypeEnum componentType,
467 ComponentInstListInput componentListInput, boolean shouldLockComp,
468 boolean inTransaction) {
469 Either<List<InputDefinition>, ResponseFormat> result = null;
470 Component component = null;
471 log.trace("#createListInput: enter");
473 /* check if user exists */
474 validateUserExists(userId);
476 component = getAndValidateComponentForCreate(userId, componentId, componentType, shouldLockComp);
478 InputDefinition listInput = componentListInput.getListInput();
479 DataTypeDefinition dataType =
480 prepareDataTypeForListInput(componentListInput.getComponentInstInputsMap(), listInput);
481 Map<String, DataTypeDefinition> dataTypesMap = new HashMap<>();
482 dataTypesMap.put(dataType.getName(), dataType);
483 if (log.isDebugEnabled()) {
484 log.debug("#createListInput: dataTypesMap={}", ReflectionToStringBuilder.toString(dataTypesMap));
487 Either<List<DataTypeDefinition>, StorageOperationStatus> dataTypeResult =
488 toscaOperationFacade.addDataTypesToComponent(dataTypesMap, componentId);
489 if (dataTypeResult.isRight()) {
490 log.debug("#createListInput: DataType creation failed.");
491 throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(dataTypeResult.right().value()));
495 listInput.setUniqueId(UniqueIdBuilder.buildPropertyUniqueId(componentId, listInput.getName()));
496 listInput.setInstanceUniqueId(
497 propertyDeclarationOrchestrator.getPropOwnerId(componentListInput.getComponentInstInputsMap()));
498 listInput.setIsDeclaredListInput(true);
499 Map<String, InputDefinition> listInputMap = new HashMap<>();
500 listInputMap.put(listInput.getName(), listInput);
501 result = createListInputsInGraph(listInputMap, dataTypesMap, component);
502 if (result.isRight()) {
503 log.debug("#createListInput: createListInputsInGraph failed.");
504 throw new ByResponseFormatComponentException(result.right().value());
508 result = propertyDeclarationOrchestrator
509 .declarePropertiesToListInput(component, componentListInput.getComponentInstInputsMap(), listInput)
510 .right().map(err -> componentsUtils.getResponseFormat(err))
511 .left().map(Arrays::asList);
513 log.trace("#createListInput: leave");
517 } catch (ByResponseFormatComponentException e) {
518 log.error("#createListInput: Exception thrown", e);
519 result = Either.right(e.getResponseFormat());
523 if (!inTransaction) {
524 if (result == null || result.isRight()) {
525 log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP);
526 janusGraphDao.rollback();
528 log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP);
529 janusGraphDao.commit();
533 if (shouldLockComp && component != null) {
534 graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
539 private ComponentParametersView getBaseComponentParametersView() {
540 ComponentParametersView componentParametersView = new ComponentParametersView();
541 componentParametersView.disableAll();
542 componentParametersView.setIgnoreInputs(false);
543 componentParametersView.setIgnoreComponentInstances(false);
544 componentParametersView.setIgnoreComponentInstancesInputs(false);
545 componentParametersView.setIgnoreComponentInstancesProperties(false);
546 componentParametersView.setIgnorePolicies(false);
547 componentParametersView.setIgnoreGroups(false);
548 componentParametersView.setIgnoreUsers(false);
549 return componentParametersView;
552 private Component getAndValidateComponentForCreate(
553 String userId, String componentId, ComponentTypeEnum componentType, boolean shouldLockComp
555 ComponentParametersView componentParametersView = getBaseComponentParametersView();
556 Component component = validateComponentExists(componentId, componentType, componentParametersView);
557 if (shouldLockComp) {
558 // lock the component
559 lockComponent(component, CREATE_INPUT);
561 validateCanWorkOnComponent(component, userId);
565 private DataTypeDefinition prepareDataTypeForListInput(ComponentInstInputsMap inputsMap, InputDefinition input) {
566 // Confirm if type is list
567 if (StringUtils.isEmpty(input.getType()) || !input.getType().equals(ToscaPropertyType.LIST.getType())) {
568 log.debug("#prepareDataTypeForListInput: Type of input is not list.");
569 throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_TYPE));
572 // Confirm schema type is not empty
573 String desiredTypeName = input.getSchemaType();
574 if (StringUtils.isEmpty(desiredTypeName)) {
575 log.debug("#prepareDataTypeForListInput: Schema type of list input is empty.");
576 throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY_INNER_TYPE));
579 DataTypeDefinition dataType = new DataTypeDefinition();
580 List<ComponentInstancePropInput> propInputs = inputsMap.resolvePropertiesToDeclare().getRight();
581 dataType.setName(desiredTypeName);
582 dataType.setDerivedFromName(ToscaPropertyType.ROOT.getType());
583 // Copy properties from inputsMap
584 dataType.setProperties(propInputs.stream().map(PropertyDefinition::new).collect(Collectors.toList()));
588 private Either<List<InputDefinition>, StorageOperationStatus> prepareInputsForCreation(String userId, String cmptId,
589 List<InputDefinition> inputsToCreate) {
590 Map<String, InputDefinition> inputsToPersist = MapUtil.toMap(inputsToCreate, InputDefinition::getName);
591 assignOwnerIdToInputs(userId, inputsToPersist);
592 inputsToPersist.values()
593 .forEach(input -> input.setConstraints(componentInstanceBusinessLogic.setInputConstraint(input)));
595 return toscaOperationFacade.addInputsToComponent(inputsToPersist, cmptId)
597 .map(persistedInputs -> inputsToCreate);
600 private void assignOwnerIdToInputs(String userId, Map<String, InputDefinition> inputsToCreate) {
601 inputsToCreate.values().forEach(inputDefinition -> inputDefinition.setOwnerId(userId));
604 public Either<List<InputDefinition>, ResponseFormat> createInputsInGraph(Map<String, InputDefinition> inputs,
605 Component component) {
607 List<InputDefinition> resourceProperties = component.getInputs();
609 final Map<String, DataTypeDefinition> dataTypes = componentsUtils.getAllDataTypes(applicationDataTypeCache, component.getModel());
611 for (Map.Entry<String, InputDefinition> inputDefinition : inputs.entrySet()) {
612 String inputName = inputDefinition.getKey();
613 inputDefinition.getValue().setName(inputName);
615 Either<InputDefinition, ResponseFormat> preparedInputEither = prepareAndValidateInputBeforeCreate(inputDefinition.getValue(), dataTypes);
616 if (preparedInputEither.isRight()) {
617 return Either.right(preparedInputEither.right().value());
621 if (resourceProperties != null) {
622 Map<String, InputDefinition> generatedInputs = resourceProperties.stream()
623 .collect(Collectors.toMap(PropertyDataDefinition::getName, i -> i));
624 Either<Map<String, InputDefinition>, String> mergeEither = ToscaDataDefinition.mergeDataMaps(generatedInputs, inputs);
625 if (mergeEither.isRight()) {
626 return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_ALREADY_EXIST, mergeEither.right().value()));
628 inputs = mergeEither.left().value();
631 Either<List<InputDefinition>, StorageOperationStatus> associateInputsEither = toscaOperationFacade
632 .createAndAssociateInputs(inputs, component.getUniqueId());
633 if (associateInputsEither.isRight()) {
634 log.debug("Failed to create inputs under component {}. Status is {}", component.getUniqueId(), associateInputsEither.right().value());
636 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(associateInputsEither.right().value())));
638 return Either.left(associateInputsEither.left().value());
641 private Either<List<InputDefinition>, ResponseFormat> createListInputsInGraph(Map<String, InputDefinition> inputs,
642 Map<String, DataTypeDefinition> privateDataTypes,
643 Component component) {
645 log.trace("#createListInputsInGraph: enter");
647 Map<String, DataTypeDefinition> dataTypes = componentsUtils.getAllDataTypes(applicationDataTypeCache, component.getModel());
648 dataTypes.putAll(privateDataTypes);
650 for (Map.Entry<String, InputDefinition> inputDefinition : inputs.entrySet()) {
651 String inputName = inputDefinition.getKey();
652 inputDefinition.getValue().setName(inputName);
654 Either<InputDefinition, ResponseFormat> preparedInputEither =
655 prepareAndValidateInputBeforeCreate(inputDefinition.getValue(), dataTypes);
656 if (preparedInputEither.isRight()) {
657 return Either.right(preparedInputEither.right().value());
661 Either<List<InputDefinition>, StorageOperationStatus> addInputsEither = toscaOperationFacade
662 .addInputsToComponent(inputs, component.getUniqueId());
663 if (addInputsEither.isRight()) {
664 log.debug("#createListInputsInGraph: Failed to create inputs under component {}. Status is {}",
665 component.getUniqueId(), addInputsEither.right().value());
666 return Either.right(componentsUtils.getResponseFormat(
667 componentsUtils.convertFromStorageResponse(addInputsEither.right().value())));
669 log.trace("#createListInputsInGraph: leave");
670 return Either.left(addInputsEither.left().value());
674 * Delete input from service
681 public InputDefinition deleteInput(String componentId, String userId, String inputId) {
682 Either<InputDefinition, ResponseFormat> deleteEither = null;
683 if (log.isDebugEnabled()) {
684 log.debug("Going to delete input id: {}", inputId);
686 validateUserExists(userId);
687 ComponentParametersView componentParametersView = getBaseComponentParametersView();
688 componentParametersView.setIgnoreInterfaces(false);
689 componentParametersView.setIgnoreDataType(false);
690 componentParametersView.setIgnoreProperties(false);
691 Either<Component, StorageOperationStatus> componentEither = toscaOperationFacade
692 .getToscaElement(componentId, componentParametersView);
693 if (componentEither.isRight()) {
694 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(componentEither.right().value()));
696 Component component = componentEither.left().value();
697 // Validate inputId is child of the component
698 Optional<InputDefinition> optionalInput = component.getInputs().stream().
700 filter(input -> input.getUniqueId().equals(inputId)).
703 if (!optionalInput.isPresent()) {
704 throw new ByActionStatusComponentException(ActionStatus.INPUT_IS_NOT_CHILD_OF_COMPONENT, inputId, componentId);
706 InputDefinition inputForDelete = optionalInput.get();
708 lockComponent(componentId, component, "deleteInput");
709 // Delete input operations
710 boolean failed = false;
712 StorageOperationStatus status = toscaOperationFacade.deleteInputOfResource(component, inputForDelete.getName());
713 if (status != StorageOperationStatus.OK) {
714 log.debug("Component id: {} delete input id: {} failed", componentId, inputId);
715 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(status), component.getName());
717 if (BooleanUtils.isTrue(inputForDelete.getIsDeclaredListInput())) {
718 deleteEither = deleteListInput(componentId, inputId, component, inputForDelete, status);
719 if (deleteEither.isRight()) {
720 throw new ByResponseFormatComponentException(deleteEither.right().value());
722 return deleteEither.left().value();
724 StorageOperationStatus storageOperationStatus = propertyDeclarationOrchestrator.unDeclarePropertiesAsInputs(component, inputForDelete);
725 if (storageOperationStatus != StorageOperationStatus.OK) {
726 log.debug("Component id: {} update properties declared as input for input id: {} failed", componentId, inputId);
727 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(storageOperationStatus), component.getName());
729 return inputForDelete;
730 } catch (ComponentException e) {
734 unlockComponent(failed, component);
738 private Either<InputDefinition, ResponseFormat> deleteListInput(String componentId, String inputId,
739 Component component, InputDefinition inputForDelete,
740 StorageOperationStatus status) {
741 // the input is created by 'Declare List'.
742 // need to 1. undeclare properties, 2. delete input, 3. delete private data type
743 StorageOperationStatus storageOperationStatus = propertyDeclarationOrchestrator.unDeclarePropertiesAsListInputs(component, inputForDelete);
744 if (storageOperationStatus != StorageOperationStatus.OK) {
745 log.debug("Component id: {} update properties declared as input for input id: {} failed", componentId, inputId);
746 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status), component.getName()));
748 Either<DataTypeDefinition, StorageOperationStatus> deleteResult = dataTypeBusinessLogic
749 .deletePrivateDataType(component, inputForDelete.getSchemaType());
750 if (deleteResult.isRight()) {
751 log.debug("Component id: {} delete datatype name: {} failed", componentId, inputForDelete.getSchemaType());
753 componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(deleteResult.right().value()), component.getName()));
755 log.trace("deleteInput: deletePrivateDataType (OK)");
756 return Either.left(inputForDelete);
759 private Either<InputDefinition, ResponseFormat> prepareAndValidateInputBeforeCreate(InputDefinition newInputDefinition,
760 Map<String, DataTypeDefinition> dataTypes) {
761 // validate input default values
762 Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newInputDefinition, dataTypes);
763 if (defaultValuesValidation.isRight()) {
764 return Either.right(defaultValuesValidation.right().value());
767 ToscaPropertyType type = getType(newInputDefinition.getType());
769 PropertyValueConverter converter = type.getConverter();
771 SchemaDefinition schema = newInputDefinition.getSchema();
772 String innerType = null;
773 if (schema != null) {
774 PropertyDataDefinition prop = schema.getProperty();
776 innerType = prop.getType();
779 String convertedValue;
780 if (newInputDefinition.getDefaultValue() != null) {
781 convertedValue = converter.convert(newInputDefinition.getDefaultValue(), innerType, dataTypes);
782 newInputDefinition.setDefaultValue(convertedValue);
785 return Either.left(newInputDefinition);
788 public Either<InputDefinition, ResponseFormat> getInputsAndPropertiesForComponentInput(String userId, String componentId, String inputId,
789 boolean inTransaction) {
790 Either<InputDefinition, ResponseFormat> result = null;
792 validateUserExists(userId);
793 ComponentParametersView filters = new ComponentParametersView();
794 filters.disableAll();
795 filters.setIgnoreComponentInstances(false);
796 filters.setIgnoreInputs(false);
797 filters.setIgnoreComponentInstancesInputs(false);
798 filters.setIgnoreComponentInstancesProperties(false);
799 filters.setIgnoreProperties(false);
800 Either<Component, StorageOperationStatus> getComponentEither = toscaOperationFacade
801 .getToscaElement(componentId, filters);
802 if (getComponentEither.isRight()) {
803 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
804 log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, componentId, actionStatus);
805 return Either.right(componentsUtils.getResponseFormat(actionStatus));
807 Component component = getComponentEither.left().value();
808 Optional<InputDefinition> op = component.getInputs().stream().filter(in -> in.getUniqueId().equals(inputId)).findFirst();
809 if (!op.isPresent()) {
810 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
811 log.debug(FAILED_TO_FOUND_INPUT_UNDER_COMPONENT_ERROR, inputId, componentId, actionStatus);
812 return Either.right(componentsUtils.getResponseFormat(actionStatus));
814 InputDefinition resObj = op.get();
815 List<ComponentInstanceInput> inputCIInput = componentInstanceBusinessLogic.getComponentInstanceInputsByInputId(component, inputId);
816 resObj.setInputs(inputCIInput);
817 List<ComponentInstanceProperty> inputProps = componentInstanceBusinessLogic.getComponentInstancePropertiesByInputId(component, inputId);
818 resObj.setProperties(inputProps);
819 result = Either.left(resObj);
822 if (!inTransaction) {
823 if (result == null || result.isRight()) {
824 log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_GROUP);
825 janusGraphDao.rollback();
827 log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_GROUP);
828 janusGraphDao.commit();
834 public Either<EntryData<String, InputDefinition>, ResponseFormat> addInputToComponent(String componentId, String inputName,
835 InputDefinition newInputDefinition, String userId) {
836 Either<EntryData<String, InputDefinition>, ResponseFormat> result = null;
837 validateUserExists(userId);
838 Either<Component, StorageOperationStatus> serviceElement = toscaOperationFacade.getToscaElement(componentId);
839 if (serviceElement.isRight()) {
840 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, ""));
843 Component component = serviceElement.left().value();
844 NodeTypeEnum nodeType = component.getComponentType().getNodeType();
845 StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, nodeType);
846 if (!lockResult.equals(StorageOperationStatus.OK)) {
847 BeEcompErrorManager.getInstance().logBeFailedLockObjectError(CREATE_INPUT, nodeType.name().toLowerCase(), componentId);
848 log.info("Failed to lock component {}. Error - {}", componentId, lockResult);
849 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
853 if (!ComponentValidationUtils.canWorkOnComponent(component, userId)) {
854 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
857 List<InputDefinition> inputs = component.getInputs();
858 if (CollectionUtils.isEmpty(inputs)) {
859 inputs = new ArrayList<>();
861 if (isInputExistInComponent(inputs, inputName)) {
862 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INPUT_ALREADY_EXIST, inputName));
865 Map<String, DataTypeDefinition> allDataTypes = componentsUtils.getAllDataTypes(applicationDataTypeCache, component.getModel());
866 // validate input default values
867 Either<Boolean, ResponseFormat> defaultValuesValidation = validatePropertyDefaultValue(newInputDefinition, allDataTypes);
868 if (defaultValuesValidation.isRight()) {
869 result = Either.right(defaultValuesValidation.right().value());
873 ToscaPropertyType type = getType(newInputDefinition.getType());
875 PropertyValueConverter converter = type.getConverter();
877 String innerType = null;
878 SchemaDefinition schema = newInputDefinition.getSchema();
879 if (schema != null) {
880 PropertyDataDefinition prop = schema.getProperty();
882 innerType = prop.getType();
885 if (newInputDefinition.getDefaultValue() != null) {
886 String convertedValue = converter.convert(newInputDefinition.getDefaultValue(), innerType, allDataTypes);
887 newInputDefinition.setDefaultValue(convertedValue);
890 newInputDefinition.setMappedToComponentProperty(false);
891 Either<InputDefinition, StorageOperationStatus> addInputEither = toscaOperationFacade
892 .addInputToComponent(inputName, newInputDefinition, component);
893 if (addInputEither.isRight()) {
894 log.info("Failed to add new input {}. Error - {}", componentId, addInputEither.right().value());
895 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
898 result = Either.left(new EntryData<>(inputName, newInputDefinition));
901 commitOrRollback(result);
903 graphLockOperation.unlockComponent(componentId, nodeType);
907 private boolean isInputExistInComponent(List<InputDefinition> inputs, String inputName) {
908 return CollectionUtils.isNotEmpty(inputs) && inputs.stream().anyMatch(input -> input.getName().equals(inputName));