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.List;
28 import java.util.Optional;
29 import org.apache.commons.collections4.CollectionUtils;
30 import org.jetbrains.annotations.NotNull;
31 import org.openecomp.sdc.be.components.attribute.AttributeDeclarationOrchestrator;
32 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
33 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
34 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
35 import org.openecomp.sdc.be.components.validation.ComponentValidations;
36 import org.openecomp.sdc.be.dao.api.ActionStatus;
37 import org.openecomp.sdc.be.dao.utils.MapUtil;
38 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
39 import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
40 import org.openecomp.sdc.be.model.Component;
41 import org.openecomp.sdc.be.model.ComponentInstOutputsMap;
42 import org.openecomp.sdc.be.model.ComponentInstance;
43 import org.openecomp.sdc.be.model.ComponentInstanceAttribOutput;
44 import org.openecomp.sdc.be.model.ComponentInstanceAttribute;
45 import org.openecomp.sdc.be.model.ComponentInstanceOutput;
46 import org.openecomp.sdc.be.model.ComponentParametersView;
47 import org.openecomp.sdc.be.model.OutputDefinition;
48 import org.openecomp.sdc.be.model.PropertyDefinition;
49 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
50 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
51 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
52 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
53 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
54 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
55 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
56 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
57 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
58 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
59 import org.openecomp.sdc.common.log.enums.StatusCode;
60 import org.openecomp.sdc.common.log.wrappers.Logger;
61 import org.openecomp.sdc.exception.ResponseFormat;
62 import org.springframework.beans.factory.annotation.Autowired;
63 import org.springframework.http.HttpStatus;
65 @org.springframework.stereotype.Component("outputsBusinessLogic")
66 public class OutputsBusinessLogic extends BaseBusinessLogic {
68 private static final String CREATE_OUTPUT = "CreateOutput";
69 private static final Logger log = Logger.getLogger(OutputsBusinessLogic.class);
70 private static final String FAILED_TO_FOUND_COMPONENT_ERROR = "Failed to found component {}, error: {}";
71 private static final String GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_OUTPUTS = "Going to execute rollback on create outputs.";
72 private static final String GOING_TO_EXECUTE_COMMIT_ON_CREATE_OUTPUTS = "Going to execute commit on create outputs.";
73 private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(OutputsBusinessLogic.class);
74 private static final String FAILED_TO_FOUND_COMPONENT_INSTANCE_OUTPUTS_COMPONENT_INSTANCE_ID =
75 "Failed to found component instance outputs componentInstanceId: {}";
76 private static final String FAILED_TO_FOUND_COMPONENT_INSTANCE_OUTPUTS_ERROR = "Failed to found component instance outputs {}, error: {}";
77 private final AttributeDeclarationOrchestrator attributeDeclarationOrchestrator;
80 public OutputsBusinessLogic(final IElementOperation elementDao, final IGroupOperation groupOperation,
81 final IGroupInstanceOperation groupInstanceOperation, final IGroupTypeOperation groupTypeOperation,
82 final InterfaceOperation interfaceOperation, final InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
83 final AttributeDeclarationOrchestrator attributeDeclarationOrchestrator,
84 final ArtifactsOperations artifactToscaOperation) {
85 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
86 artifactToscaOperation);
87 this.attributeDeclarationOrchestrator = attributeDeclarationOrchestrator;
90 public Either<List<ComponentInstanceOutput>, ResponseFormat> getComponentInstanceOutputs(final String userId, final String componentId,
91 final String componentInstanceId) {
92 validateUserExists(userId);
93 final ComponentParametersView filters = new ComponentParametersView();
95 filters.setIgnoreOutputs(false);
96 filters.setIgnoreComponentInstances(false);
97 filters.setIgnoreComponentInstancesOutputs(false);
98 final Either<Component, StorageOperationStatus> getComponentEither = toscaOperationFacade.getToscaElement(componentId, filters);
99 if (getComponentEither.isRight()) {
100 ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getComponentEither.right().value());
101 log.debug(FAILED_TO_FOUND_COMPONENT_ERROR, componentId, actionStatus);
102 return Either.right(componentsUtils.getResponseFormat(actionStatus));
104 final Component component = getComponentEither.left().value();
105 if (!ComponentValidations.validateComponentInstanceExist(component, componentInstanceId)) {
106 final ActionStatus actionStatus = ActionStatus.COMPONENT_INSTANCE_NOT_FOUND;
107 log.debug(FAILED_TO_FOUND_COMPONENT_INSTANCE_OUTPUTS_ERROR, componentInstanceId, actionStatus);
108 loggerSupportability.log(LoggerSupportabilityActions.CREATE_OUTPUTS, component.getComponentMetadataForSupportLog(), StatusCode.ERROR,
109 FAILED_TO_FOUND_COMPONENT_INSTANCE_OUTPUTS_COMPONENT_INSTANCE_ID, componentInstanceId);
110 return Either.right(componentsUtils.getResponseFormat(actionStatus));
112 final Map<String, List<ComponentInstanceOutput>> ciOutputs = Optional.ofNullable(component.getComponentInstancesOutputs())
113 .orElse(Collections.emptyMap());
114 return Either.left(ciOutputs.getOrDefault(componentInstanceId, Collections.emptyList()));
118 public Either<List<OutputDefinition>, ResponseFormat> declareAttributes(final String userId, final String componentId,
119 final ComponentTypeEnum componentTypeEnum,
120 final ComponentInstOutputsMap componentInstOutputsMap) {
121 return createMultipleOutputs(userId, componentId, componentTypeEnum, componentInstOutputsMap, true, false);
124 private Either<List<OutputDefinition>, ResponseFormat> createMultipleOutputs(final String userId, final String componentId,
125 final ComponentTypeEnum componentType,
126 final ComponentInstOutputsMap componentInstOutputsMapUi,
127 final boolean shouldLockComp, final boolean inTransaction) {
128 Either<List<OutputDefinition>, ResponseFormat> result = Either.right(new ResponseFormat(HttpStatus.BAD_REQUEST.value()));
129 org.openecomp.sdc.be.model.Component component = null;
131 validateUserExists(userId);
132 component = getAndValidateComponentForCreate(userId, componentId, componentType, shouldLockComp);
133 result = attributeDeclarationOrchestrator.declareAttributesToOutputs(component, componentInstOutputsMapUi).left()
134 .bind(outputsToCreate -> prepareOutputsForCreation(userId, componentId, outputsToCreate)).right()
135 .map(componentsUtils::getResponseFormat);
137 } catch (final ByResponseFormatComponentException e) {
138 log.error("#createMultipleOutputs: Exception thrown: ", e);
139 result = Either.right(e.getResponseFormat());
142 if (!inTransaction) {
143 if (result.isRight()) {
144 log.debug(GOING_TO_EXECUTE_ROLLBACK_ON_CREATE_OUTPUTS);
145 janusGraphDao.rollback();
147 log.debug(GOING_TO_EXECUTE_COMMIT_ON_CREATE_OUTPUTS);
148 janusGraphDao.commit();
152 if (shouldLockComp && component != null) {
153 graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
158 private Component getAndValidateComponentForCreate(final String userId, final String componentId,
159 final ComponentTypeEnum componentType,
160 final boolean shouldLockComp) {
161 final ComponentParametersView componentParametersView = getBaseComponentParametersView();
162 final Component component = validateComponentExists(componentId, componentType, componentParametersView);
163 if (shouldLockComp) {
164 // lock the component
165 lockComponent(component, CREATE_OUTPUT);
167 validateCanWorkOnComponent(component, userId);
171 private Either<List<OutputDefinition>, StorageOperationStatus> prepareOutputsForCreation(final String userId, final String cmptId,
172 final List<OutputDefinition> outputsToCreate) {
173 final Map<String, OutputDefinition> outputsToPersist = MapUtil.toMap(outputsToCreate, OutputDefinition::getName);
174 assignOwnerIdToOutputs(userId, outputsToPersist);
175 final var statusEither = toscaOperationFacade.addOutputsToComponent(outputsToPersist, cmptId);
176 if (statusEither.isRight()) {
179 return statusEither.left().map(persistedOutputs -> outputsToCreate);
182 private void assignOwnerIdToOutputs(final String userId, final Map<String, OutputDefinition> outputsToCreate) {
183 outputsToCreate.values().forEach(outputDefinition -> outputDefinition.setOwnerId(userId));
186 private ComponentParametersView getBaseComponentParametersView() {
187 final ComponentParametersView componentParametersView = new ComponentParametersView();
188 componentParametersView.disableAll();
189 componentParametersView.setIgnoreOutputs(false);
190 componentParametersView.setIgnoreAttributes(false);
191 componentParametersView.setIgnoreComponentInstances(false);
192 componentParametersView.setIgnoreComponentInstancesOutputs(false);
193 componentParametersView.setIgnoreComponentInstancesAttributes(false);
194 componentParametersView.setIgnoreUsers(false);
195 return componentParametersView;
199 * Delete output from component
206 public OutputDefinition deleteOutput(final String componentId, final String userId, final String outputId) {
207 if (log.isDebugEnabled()) {
208 log.debug("Going to delete output id: {}", outputId);
210 validateUserExists(userId);
211 final ComponentParametersView componentParametersView = getBaseComponentParametersView();
212 componentParametersView.setIgnoreAttributes(false);
213 final Either<org.openecomp.sdc.be.model.Component, StorageOperationStatus> componentEither = toscaOperationFacade
214 .getToscaElement(componentId, componentParametersView);
215 if (componentEither.isRight()) {
216 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(componentEither.right().value()));
218 final org.openecomp.sdc.be.model.Component component = componentEither.left().value();
219 // Validate outputId is child of the component
220 final Optional<OutputDefinition> optionalOutput = component.getOutputs().stream().
222 filter(output -> output.getUniqueId().equals(outputId)).
225 if (!optionalOutput.isPresent()) {
226 throw new ByActionStatusComponentException(ActionStatus.OUTPUT_IS_NOT_CHILD_OF_COMPONENT, outputId, componentId);
228 final OutputDefinition outputForDelete = optionalOutput.get();
230 lockComponent(componentId, component, "deleteOutput");
231 // Delete output operations
232 boolean failed = false;
234 final StorageOperationStatus status = toscaOperationFacade.deleteOutputOfResource(component, outputForDelete.getName());
235 if (status != StorageOperationStatus.OK) {
236 log.debug("Component id: {} delete output id: {} failed", componentId, outputId);
237 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(status), component.getName());
239 final StorageOperationStatus storageOperationStatus = attributeDeclarationOrchestrator
240 .unDeclareAttributesAsOutputs(component, outputForDelete);
241 if (storageOperationStatus != StorageOperationStatus.OK) {
242 log.debug("Component id: {} update attributes declared as output for outputId: {} failed", componentId, outputId);
243 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(storageOperationStatus), component.getName());
245 return outputForDelete;
246 } catch (final ComponentException e) {
250 unlockComponent(failed, component);
254 public Either<List<OutputDefinition>, ResponseFormat> createOutputsInGraph(final Map<String, OutputDefinition> outputs,
255 final Component component,
256 final String userId) {
258 final List<OutputDefinition> result = new ArrayList<>();
259 for (final Map.Entry<String, OutputDefinition> outputDefinition : outputs.entrySet()) {
260 final var outputDefinitionValue = outputDefinition.getValue();
261 outputDefinitionValue.setName(outputDefinition.getKey());
263 final String value = outputDefinitionValue.getValue();
265 final List<String> getAttribute = (List<String>) ImportUtils.loadYamlAsStrictMap(value)
266 .get(ToscaGetFunctionType.GET_ATTRIBUTE.getFunctionName());
267 if (getAttribute.size() == 2) {
268 final var optionalComponentInstance = component.getComponentInstanceByName(getAttribute.get(0));
269 if (optionalComponentInstance.isPresent()) {
270 final var createdOutputs
271 = createOutputs(component.getUniqueId(), userId, getAttribute.get(1), optionalComponentInstance.get());
272 if (createdOutputs.isRight()) {
273 return Either.right((createdOutputs.right().value()));
275 result.addAll(createdOutputs.left().value());
278 outputDefinitionValue.setInstanceUniqueId(component.getUniqueId());
283 return Either.left(result);
287 private Either<List<OutputDefinition>, ResponseFormat> createOutputs(final String componentUniqueId, final String userId,
288 final String attributeName,
289 final ComponentInstance componentInstance) {
291 final List<OutputDefinition> result = new ArrayList<>();
292 final var componentInstanceAttributes = componentInstance.getAttributes();
293 if (CollectionUtils.isNotEmpty(componentInstanceAttributes)) {
294 final var componentInstanceAttributeOptional = componentInstanceAttributes.stream()
295 .filter(ad -> ad.getName().equals(attributeName)).map(ComponentInstanceAttribute::new).findFirst();
296 if (componentInstanceAttributeOptional.isPresent()) {
297 final var componentInstOutputsMap = new ComponentInstOutputsMap();
298 componentInstOutputsMap.setComponentInstanceAttributes(Collections.singletonMap(componentInstance.getUniqueId(),
299 Collections.singletonList(new ComponentInstanceAttribOutput(componentInstanceAttributeOptional.get()))));
300 final var createdOutputs = createMultipleOutputs(userId, componentUniqueId, ComponentTypeEnum.SERVICE,
301 componentInstOutputsMap, true, false);
302 if (createdOutputs.isRight()) {
303 return Either.right((createdOutputs.right().value()));
305 result.addAll(createdOutputs.left().value());
308 final List<PropertyDefinition> componentInstanceProperties = componentInstance.getProperties();
309 if (CollectionUtils.isNotEmpty(componentInstanceProperties)) {
310 final Optional<PropertyDefinition> componentInstancePropertyOptional = componentInstanceProperties.stream()
311 .filter(prop -> prop.getName().equals(attributeName)).findFirst();
312 if (componentInstancePropertyOptional.isPresent()) {
313 PropertyDefinition propertyDefinition = componentInstancePropertyOptional.get();
314 final ComponentInstOutputsMap componentInstOutputsMap = new ComponentInstOutputsMap();
315 ComponentInstanceAttribOutput attribute = getComponentInstanceAttribOutput(propertyDefinition);
316 componentInstOutputsMap.setComponentInstanceAttributes(Collections.singletonMap(componentInstance.getUniqueId(),
317 Collections.singletonList(new ComponentInstanceAttribOutput(attribute))));
318 return createMultipleOutputs(userId, componentUniqueId, ComponentTypeEnum.SERVICE, componentInstOutputsMap, true, false);
321 return Either.left(result);
325 private ComponentInstanceAttribOutput getComponentInstanceAttribOutput(PropertyDefinition propertyDefinition) {
326 ComponentInstanceAttribOutput attribute = new ComponentInstanceAttribOutput();
327 attribute.setParentUniqueId(propertyDefinition.getParentUniqueId());
328 attribute.setName(propertyDefinition.getName());
329 attribute.setOwnerId(propertyDefinition.getOwnerId());
330 attribute.setType(propertyDefinition.getType());
331 attribute.setSchema(propertyDefinition.getSchema());
332 attribute.setUniqueId(propertyDefinition.getUniqueId());