2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2021, Nordix Foundation. 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=========================================================
21 package org.openecomp.sdc.be.components.impl;
23 import fj.data.Either;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.List;
29 import java.util.Optional;
30 import org.apache.commons.collections.MapUtils;
31 import org.apache.commons.collections4.CollectionUtils;
32 import org.apache.commons.lang3.StringUtils;
33 import org.apache.commons.lang3.tuple.ImmutablePair;
34 import org.jetbrains.annotations.NotNull;
35 import org.openecomp.sdc.be.components.attribute.AttributeDeclarationOrchestrator;
36 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
37 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
38 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
39 import org.openecomp.sdc.be.components.validation.ComponentValidations;
40 import org.openecomp.sdc.be.dao.api.ActionStatus;
41 import org.openecomp.sdc.be.dao.utils.MapUtil;
42 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
43 import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
44 import org.openecomp.sdc.be.model.Component;
45 import org.openecomp.sdc.be.model.ComponentInstOutputsMap;
46 import org.openecomp.sdc.be.model.ComponentInstance;
47 import org.openecomp.sdc.be.model.ComponentInstanceAttribOutput;
48 import org.openecomp.sdc.be.model.ComponentInstanceAttribute;
49 import org.openecomp.sdc.be.model.ComponentInstanceOutput;
50 import org.openecomp.sdc.be.model.ComponentParametersView;
51 import org.openecomp.sdc.be.model.OutputDefinition;
52 import org.openecomp.sdc.be.model.PropertyDefinition;
53 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
54 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
55 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
56 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
57 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
58 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
59 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
60 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
61 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
62 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
63 import org.openecomp.sdc.common.log.enums.StatusCode;
64 import org.openecomp.sdc.common.log.wrappers.Logger;
65 import org.openecomp.sdc.exception.ResponseFormat;
66 import org.springframework.beans.factory.annotation.Autowired;
67 import org.springframework.http.HttpStatus;
69 @org.springframework.stereotype.Component("outputsBusinessLogic")
70 public class OutputsBusinessLogic extends BaseBusinessLogic {
72 private static final String CREATE_OUTPUT = "CreateOutput";
73 private static final Logger log = Logger.getLogger(OutputsBusinessLogic.class);
74 private static final String FAILED_TO_FOUND_COMPONENT_ERROR = "Failed to found component {}, error: {}";
75 private static final String GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_OUTPUTS = "Going to execute rollback on create outputs.";
76 private static final String GOING_TO_EXECUTE_COMMIT_ON_CREATE_OUTPUTS = "Going to execute commit on create outputs.";
77 private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(OutputsBusinessLogic.class);
78 private static final String FAILED_TO_FOUND_COMPONENT_INSTANCE_OUTPUTS_COMPONENT_INSTANCE_ID =
79 "Failed to found component instance outputs componentInstanceId: {}";
80 private static final String FAILED_TO_FOUND_COMPONENT_INSTANCE_OUTPUTS_ERROR = "Failed to found component instance outputs {}, error: {}";
81 private final AttributeDeclarationOrchestrator attributeDeclarationOrchestrator;
84 public OutputsBusinessLogic(final IElementOperation elementDao, final IGroupOperation groupOperation,
85 final IGroupInstanceOperation groupInstanceOperation, final IGroupTypeOperation groupTypeOperation,
86 final InterfaceOperation interfaceOperation, final InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
87 final AttributeDeclarationOrchestrator attributeDeclarationOrchestrator,
88 final ArtifactsOperations artifactToscaOperation) {
89 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
90 artifactToscaOperation);
91 this.attributeDeclarationOrchestrator = attributeDeclarationOrchestrator;
94 public Either<List<ComponentInstanceOutput>, ResponseFormat> getComponentInstanceOutputs(final String userId, final String componentId,
95 final String componentInstanceId) {
96 validateUserExists(userId);
97 final ComponentParametersView filters = new ComponentParametersView();
99 filters.setIgnoreOutputs(false);
100 filters.setIgnoreComponentInstances(false);
101 filters.setIgnoreComponentInstancesOutputs(false);
102 final Either<Component, StorageOperationStatus> getComponentEither = toscaOperationFacade.getToscaElement(componentId, filters);
103 if (getComponentEither.isRight()) {
104 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
105 log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, componentId, actionStatus);
106 return Either.right(componentsUtils.getResponseFormat(actionStatus));
108 final Component component = getComponentEither.left().value();
109 if (!ComponentValidations.validateComponentInstanceExist(component, componentInstanceId)) {
110 final ActionStatus actionStatus = ActionStatus.COMPONENT_INSTANCE_NOT_FOUND;
111 log.debug(FAILED_TO_FOUND_COMPONENT_INSTANCE_OUTPUTS_ERROR, componentInstanceId, actionStatus);
112 loggerSupportability.log(LoggerSupportabilityActions.CREATE_OUTPUTS, component.getComponentMetadataForSupportLog(), StatusCode.ERROR,
113 FAILED_TO_FOUND_COMPONENT_INSTANCE_OUTPUTS_COMPONENT_INSTANCE_ID, componentInstanceId);
114 return Either.right(componentsUtils.getResponseFormat(actionStatus));
116 final Map<String, List<ComponentInstanceOutput>> ciOutputs = Optional.ofNullable(component.getComponentInstancesOutputs())
117 .orElse(Collections.emptyMap());
118 return Either.left(ciOutputs.getOrDefault(componentInstanceId, Collections.emptyList()));
122 public Either<List<OutputDefinition>, ResponseFormat> declareAttributes(final String userId, final String componentId,
123 final ComponentTypeEnum componentTypeEnum,
124 final ComponentInstOutputsMap componentInstOutputsMap) {
125 return createMultipleOutputs(userId, componentId, componentTypeEnum, componentInstOutputsMap, true, false);
128 private Either<List<OutputDefinition>, ResponseFormat> createMultipleOutputs(final String userId, final String componentId,
129 final ComponentTypeEnum componentType,
130 final ComponentInstOutputsMap componentInstOutputsMapUi,
131 final boolean shouldLockComp, final boolean inTransaction) {
132 Either<List<OutputDefinition>, ResponseFormat> result = Either.right(new ResponseFormat(HttpStatus.BAD_REQUEST.value()));
133 org.openecomp.sdc.be.model.Component component = null;
135 validateUserExists(userId);
136 component = getAndValidateComponentForCreate(userId, componentId, componentType, shouldLockComp);
137 ImmutablePair<StorageOperationStatus, String> status = validateOutputName(component, componentInstOutputsMapUi);
138 if (status.getLeft() != StorageOperationStatus.OK) {
139 throw new ByResponseFormatComponentException(
140 componentsUtils.getResponseFormat(ActionStatus.OUTPUT_NAME_ALREADY_EXIST, status.getRight()));
142 result = attributeDeclarationOrchestrator.declareAttributesToOutputs(component, componentInstOutputsMapUi)
143 .left().bind(outputsToCreate -> prepareOutputsForCreation(userId, componentId, outputsToCreate))
144 .right().map(componentsUtils::getResponseFormat);
146 } catch (final ByResponseFormatComponentException e) {
147 log.error("#createMultipleOutputs: Exception thrown: ", e);
148 result = Either.right(e.getResponseFormat());
151 if (!inTransaction) {
152 if (result.isRight()) {
153 log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_OUTPUTS);
154 janusGraphDao.rollback();
156 log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_OUTPUTS);
157 janusGraphDao.commit();
161 if (shouldLockComp && component != null) {
162 graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
167 private ImmutablePair<StorageOperationStatus, String> validateOutputName(final Component component,
168 final ComponentInstOutputsMap componentInstOutputsMapUi) {
169 final Map<String, List<ComponentInstanceAttribOutput>> outputDeclaredProperties = new HashMap<>();
170 if (MapUtils.isNotEmpty(componentInstOutputsMapUi.getComponentInstanceOutputsMap())) {
171 outputDeclaredProperties.putAll(componentInstOutputsMapUi.getComponentInstanceOutputsMap());
172 } else if (MapUtils.isNotEmpty(componentInstOutputsMapUi.getComponentInstanceAttributes())) {
173 outputDeclaredProperties.putAll(componentInstOutputsMapUi.getComponentInstanceAttributes());
175 if (MapUtils.isNotEmpty(outputDeclaredProperties) && CollectionUtils.isNotEmpty(component.getOutputs())) {
176 for (final List<ComponentInstanceAttribOutput> componentInstancePropOutputs : outputDeclaredProperties.values()) {
177 for (final ComponentInstanceAttribOutput componentInstancePropOutput : componentInstancePropOutputs) {
178 final Optional<OutputDefinition> outputDefinition = component.getOutputs().stream()
179 .filter(output -> output.getName().equals(componentInstancePropOutput.getOutputName())
180 || output.getName().equals(componentInstancePropOutput.getName())).findAny();
181 if (outputDefinition.isPresent()) {
182 return new ImmutablePair<>(StorageOperationStatus.INVALID_VALUE, outputDefinition.get().getName());
187 return new ImmutablePair<>(StorageOperationStatus.OK, StringUtils.EMPTY);
190 private Component getAndValidateComponentForCreate(final String userId, final String componentId,
191 final ComponentTypeEnum componentType,
192 final boolean shouldLockComp) {
193 final ComponentParametersView componentParametersView = getBaseComponentParametersView();
194 final Component component = validateComponentExists(componentId, componentType, componentParametersView);
195 if (shouldLockComp) {
196 // lock the component
197 lockComponent(component, CREATE_OUTPUT);
199 validateCanWorkOnComponent(component, userId);
203 private Either<List<OutputDefinition>, StorageOperationStatus> prepareOutputsForCreation(final String userId, final String cmptId,
204 final List<OutputDefinition> outputsToCreate) {
205 final Map<String, OutputDefinition> outputsToPersist = MapUtil.toMap(outputsToCreate, OutputDefinition::getName);
206 assignOwnerIdToOutputs(userId, outputsToPersist);
207 final var statusEither = toscaOperationFacade.addOutputsToComponent(outputsToPersist, cmptId);
208 if (statusEither.isRight()) {
211 return statusEither.left().map(persistedOutputs -> outputsToCreate);
214 private void assignOwnerIdToOutputs(final String userId, final Map<String, OutputDefinition> outputsToCreate) {
215 outputsToCreate.values().forEach(outputDefinition -> outputDefinition.setOwnerId(userId));
218 private ComponentParametersView getBaseComponentParametersView() {
219 final ComponentParametersView componentParametersView = new ComponentParametersView();
220 componentParametersView.disableAll();
221 componentParametersView.setIgnoreOutputs(false);
222 componentParametersView.setIgnoreAttributes(false);
223 componentParametersView.setIgnoreComponentInstances(false);
224 componentParametersView.setIgnoreComponentInstancesOutputs(false);
225 componentParametersView.setIgnoreComponentInstancesAttributes(false);
226 componentParametersView.setIgnoreComponentInstancesProperties(false);
227 componentParametersView.setIgnoreUsers(false);
228 return componentParametersView;
232 * Delete output from component
239 public OutputDefinition deleteOutput(final String componentId, final String userId, final String outputId) {
240 if (log.isDebugEnabled()) {
241 log.debug("Going to delete output id: {}", outputId);
243 validateUserExists(userId);
244 final ComponentParametersView componentParametersView = getBaseComponentParametersView();
245 componentParametersView.setIgnoreAttributes(false);
246 final Either<org.openecomp.sdc.be.model.Component, StorageOperationStatus> componentEither = toscaOperationFacade
247 .getToscaElement(componentId, componentParametersView);
248 if (componentEither.isRight()) {
249 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(componentEither.right().value()));
251 final org.openecomp.sdc.be.model.Component component = componentEither.left().value();
252 // Validate outputId is child of the component
253 final Optional<OutputDefinition> optionalOutput = component.getOutputs().stream().
255 filter(output -> output.getUniqueId().equals(outputId)).
258 if (!optionalOutput.isPresent()) {
259 throw new ByActionStatusComponentException(ActionStatus.OUTPUT_IS_NOT_CHILD_OF_COMPONENT, outputId, componentId);
261 final OutputDefinition outputForDelete = optionalOutput.get();
263 lockComponent(componentId, component, "deleteOutput");
264 // Delete output operations
265 boolean failed = false;
267 final StorageOperationStatus status = toscaOperationFacade.deleteOutputOfResource(component, outputForDelete.getName());
268 if (status != StorageOperationStatus.OK) {
269 log.debug("Component id: {} delete output id: {} failed", componentId, outputId);
270 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(status), component.getName());
272 final StorageOperationStatus storageOperationStatus = attributeDeclarationOrchestrator
273 .unDeclareAttributesAsOutputs(component, outputForDelete);
274 if (storageOperationStatus != StorageOperationStatus.OK) {
275 log.debug("Component id: {} update attributes declared as output for outputId: {} failed", componentId, outputId);
276 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(storageOperationStatus), component.getName());
278 return outputForDelete;
279 } catch (final ComponentException e) {
283 unlockComponent(failed, component);
287 public Either<List<OutputDefinition>, ResponseFormat> createOutputsInGraph(final Map<String, OutputDefinition> outputs,
288 final Component component,
289 final String userId) {
291 final List<OutputDefinition> result = new ArrayList<>();
292 for (final Map.Entry<String, OutputDefinition> outputDefinition : outputs.entrySet()) {
293 final var outputDefinitionValue = outputDefinition.getValue();
294 outputDefinitionValue.setName(outputDefinition.getKey());
296 final String value = outputDefinitionValue.getValue();
298 final List<String> getAttribute = (List<String>) ImportUtils.loadYamlAsStrictMap(value)
299 .get(ToscaGetFunctionType.GET_ATTRIBUTE.getFunctionName());
300 if (getAttribute.size() == 2) {
301 final var optionalComponentInstance = component.getComponentInstanceByName(getAttribute.get(0));
302 if (optionalComponentInstance.isPresent()) {
303 final var createdOutputs
304 = createOutputs(component.getUniqueId(), userId, getAttribute.get(1), optionalComponentInstance.get(),
305 outputDefinitionValue.getName());
306 if (createdOutputs.isRight()) {
307 return Either.right((createdOutputs.right().value()));
309 result.addAll(createdOutputs.left().value());
312 outputDefinitionValue.setInstanceUniqueId(component.getUniqueId());
317 return Either.left(result);
321 private Either<List<OutputDefinition>, ResponseFormat> createOutputs(final String componentUniqueId, final String userId,
322 final String attributeName,
323 final ComponentInstance componentInstance,
324 final String outputName) {
326 final var componentInstanceAttributes = componentInstance.getAttributes();
327 if (CollectionUtils.isNotEmpty(componentInstanceAttributes)) {
328 final var componentInstanceAttributeOptional = componentInstanceAttributes.stream()
329 .filter(ad -> ad.getName().equals(attributeName)).map(ComponentInstanceAttribute::new).findFirst();
330 if (componentInstanceAttributeOptional.isPresent()) {
331 final var componentInstOutputsMap = new ComponentInstOutputsMap();
332 componentInstOutputsMap.setComponentInstanceAttributes(Collections.singletonMap(componentInstance.getUniqueId(),
333 Collections.singletonList(new ComponentInstanceAttribOutput(componentInstanceAttributeOptional.get(), outputName))));
334 return createMultipleOutputs(userId, componentUniqueId, ComponentTypeEnum.SERVICE,
335 componentInstOutputsMap, true, false);
338 final List<PropertyDefinition> componentInstanceProperties = componentInstance.getProperties();
339 if (CollectionUtils.isNotEmpty(componentInstanceProperties)) {
340 final Optional<PropertyDefinition> componentInstancePropertyOptional = componentInstanceProperties.stream()
341 .filter(prop -> prop.getName().equals(attributeName)).findFirst();
342 if (componentInstancePropertyOptional.isPresent()) {
343 PropertyDefinition propertyDefinition = componentInstancePropertyOptional.get();
344 final ComponentInstOutputsMap componentInstOutputsMap = new ComponentInstOutputsMap();
345 ComponentInstanceAttribOutput attribute = getComponentInstanceAttribOutput(propertyDefinition);
346 componentInstOutputsMap.setComponentInstanceAttributes(Collections.singletonMap(componentInstance.getUniqueId(),
347 Collections.singletonList(new ComponentInstanceAttribOutput(attribute, outputName))));
348 return createMultipleOutputs(userId, componentUniqueId, ComponentTypeEnum.SERVICE, componentInstOutputsMap, true, false);
351 return Either.left(new ArrayList<>());
355 private ComponentInstanceAttribOutput getComponentInstanceAttribOutput(PropertyDefinition propertyDefinition) {
356 ComponentInstanceAttribOutput attribute = new ComponentInstanceAttribOutput();
357 attribute.setParentUniqueId(propertyDefinition.getParentUniqueId());
358 attribute.setName(propertyDefinition.getName());
359 attribute.setOwnerId(propertyDefinition.getOwnerId());
360 attribute.setType(propertyDefinition.getType());
361 attribute.setSchema(propertyDefinition.getSchema());
362 attribute.setUniqueId(propertyDefinition.getUniqueId());