2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019 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=========================================================
21 package org.openecomp.sdc.be.components.merge.instance;
23 import fj.data.Either;
24 import org.apache.commons.lang3.StringUtils;
25 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
26 import org.openecomp.sdc.be.components.merge.utils.CapabilityOwner;
27 import org.openecomp.sdc.be.components.merge.utils.ComponentInstanceBuildingBlocks;
28 import org.openecomp.sdc.be.components.merge.utils.MergeInstanceUtils;
29 import org.openecomp.sdc.be.dao.utils.MapUtil;
30 import org.openecomp.sdc.be.impl.ComponentsUtils;
31 import org.openecomp.sdc.be.model.Component;
32 import org.openecomp.sdc.be.model.ComponentInstance;
33 import org.openecomp.sdc.be.model.RequirementCapabilityRelDef;
34 import org.openecomp.sdc.be.model.User;
35 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
36 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
37 import org.openecomp.sdc.common.datastructure.Wrapper;
38 import org.openecomp.sdc.common.log.wrappers.Logger;
39 import org.openecomp.sdc.exception.ResponseFormat;
41 import java.util.Collections;
42 import java.util.List;
44 import java.util.Objects;
45 import java.util.function.Function;
46 import java.util.stream.Collectors;
47 import java.util.stream.Stream;
50 @org.springframework.stereotype.Component("ComponentInstanceRelashionMerge")
51 public class ComponentInstanceRelationMerge implements ComponentInstanceMergeInterface {
52 private static final Logger log = Logger.getLogger(ComponentInstanceRelationMerge.class);
54 private final ComponentsUtils componentsUtils;
55 private final MergeInstanceUtils mergeInstanceUtils;
56 private final ToscaOperationFacade toscaOperationFacade;
58 public ComponentInstanceRelationMerge(ComponentsUtils componentsUtils, MergeInstanceUtils mergeInstanceUtils, ToscaOperationFacade toscaOperationFacade) {
59 this.componentsUtils = componentsUtils;
60 this.mergeInstanceUtils = mergeInstanceUtils;
61 this.toscaOperationFacade = toscaOperationFacade;
66 public void saveDataBeforeMerge(DataForMergeHolder dataHolder, Component containerComponent, ComponentInstance currentResourceInstance, Component originComponent) {
67 //All Relationships - container (service) holds info about all relations
68 //Filter by UniqueId in from/to
69 List<RequirementCapabilityRelDef> relationsFrom = getRelations(RequirementCapabilityRelDef::getFromNode,
71 currentResourceInstance);
73 List<RequirementCapabilityRelDef> relationsTo = getRelations(RequirementCapabilityRelDef::getToNode,
75 currentResourceInstance);
77 if (!relationsFrom.isEmpty() || !relationsTo.isEmpty()) {
78 ComponentInstanceBuildingBlocks instBuildingBlocks = mergeInstanceUtils.getInstanceAtomicBuildingBlocks(currentResourceInstance, originComponent);
80 if (instBuildingBlocks != null) {
81 List<RelationMergeInfo> fromRelInfoList = convert(relationsFrom, rel -> mergeInstanceUtils.mapRelationRequirement(rel, instBuildingBlocks.getVfcInstances()));
82 List<RelationMergeInfo> toRelInfoList = convert(relationsTo, rel -> mergeInstanceUtils.mapRelationCapability(rel, instBuildingBlocks.getCapabilitiesOwners()));
84 // Encapsulate all needed info in one container
85 ContainerRelationsMergeInfo containerRelationsMergeInfo = new ContainerRelationsMergeInfo(fromRelInfoList, toRelInfoList);
87 dataHolder.setVfRelationsInfo(containerRelationsMergeInfo);
91 log.debug("No relations relevant to currentResourceInstance {} found in container component", currentResourceInstance);
98 public Component mergeDataAfterCreate(User user, DataForMergeHolder dataHolder, Component updatedContainerComponent, String newInstanceId) {
99 Wrapper<Either<Component, ResponseFormat>> resultWrapper = new Wrapper<>();
101 ContainerRelationsMergeInfo containerRelationsMergeInfo = getRelationsMergeInfo(dataHolder, updatedContainerComponent, resultWrapper);
103 ComponentInstance newComponentInstance = null;
104 if(resultWrapper.isEmpty()) {
106 newComponentInstance = loadComponentInstance(updatedContainerComponent, newInstanceId, resultWrapper);
109 if(resultWrapper.isEmpty() && containerRelationsMergeInfo != null) {
110 // Load VFCI and filter them by name
111 ComponentInstanceBuildingBlocks instanceBuildBlocks = mergeInstanceUtils.getInstanceAtomicBuildingBlocks(newComponentInstance);
112 if(instanceBuildBlocks != null) {
113 // Process Relationships
114 Stream<RequirementCapabilityRelDef> toRelationsInfoStream = getCapabilitiesRelationInfoStream(updatedContainerComponent, newInstanceId, containerRelationsMergeInfo, instanceBuildBlocks);
115 Stream<RequirementCapabilityRelDef> fromRelationsInfoStream = getRequirementRelationsInfoStream(updatedContainerComponent, newInstanceId, containerRelationsMergeInfo, instanceBuildBlocks);
116 List<RequirementCapabilityRelDef> updatedRelations = getUpdatedRelations(toRelationsInfoStream, fromRelationsInfoStream);
117 Either<List<RequirementCapabilityRelDef>, StorageOperationStatus> listStorageOperationStatusEither = toscaOperationFacade.associateResourceInstances(null, updatedContainerComponent.getUniqueId(), updatedRelations);
118 if (listStorageOperationStatusEither.isLeft()) {
119 resultWrapper.setInnerElement(Either.left(updatedContainerComponent));
122 StorageOperationStatus status = listStorageOperationStatusEither.right().value();
123 log.debug("Failed to associate instances of resource {} status is {}", updatedContainerComponent.getUniqueId(), status);
124 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status), updatedContainerComponent.getUniqueId());
125 throw new ByResponseFormatComponentException(responseFormat);
129 return resultWrapper.getInnerElement().left().value();
132 private Stream<RequirementCapabilityRelDef> getRequirementRelationsInfoStream(Component updatedContainerComponent, String newInstanceId, ContainerRelationsMergeInfo containerRelationsMergeInfo, ComponentInstanceBuildingBlocks instanceBuildBlocks) {
133 Map<String, ComponentInstance> vfciMap = MapUtil.toMap(instanceBuildBlocks.getVfcInstances(), ComponentInstance::getName, (p1, p2) -> p1);
134 List<RelationMergeInfo> fromRelationsInfo = containerRelationsMergeInfo.getFromRelationsInfo();
135 Stream<RequirementCapabilityRelDef> fromRelationsInfoStream = null;
136 if( fromRelationsInfo != null) {
137 fromRelationsInfoStream = fromRelationsInfo.stream()
138 .map(oldReqInfo -> mergeInstanceUtils.restoreRequirementRelation(oldReqInfo, newInstanceId, vfciMap, updatedContainerComponent))
139 .filter(Objects::nonNull);
141 return fromRelationsInfoStream;
144 private Stream<RequirementCapabilityRelDef> getCapabilitiesRelationInfoStream(Component updatedContainerComponent, String newInstanceId, ContainerRelationsMergeInfo containerRelationsMergeInfo, ComponentInstanceBuildingBlocks instanceBuildBlocks) {
145 Map<String, CapabilityOwner> capOwnersByName = MapUtil.toMap(instanceBuildBlocks.getCapabilitiesOwners(), CapabilityOwner::getName, (p1, p2) -> p1);
146 List<RelationMergeInfo> toRelationsInfo = containerRelationsMergeInfo.getToRelationsInfo();
147 Stream<RequirementCapabilityRelDef> toRelationsInfoStream = null;
148 if (toRelationsInfo != null) {
149 toRelationsInfoStream = toRelationsInfo.stream()
150 .map(oldCapInfo -> mergeInstanceUtils.restoreCapabilityRelation(oldCapInfo, newInstanceId, capOwnersByName, updatedContainerComponent))
151 .filter(Objects::nonNull);
153 return toRelationsInfoStream;
157 * @param containerComponent
159 * @param resultWrapper
162 private ComponentInstance loadComponentInstance(Component containerComponent, String instanceId,
163 Wrapper<Either<Component, ResponseFormat>> resultWrapper) {
164 ComponentInstance componentInstance = containerComponent.getComponentInstanceById(instanceId).orElse(null);
165 if (componentInstance == null) {
166 log.debug("Failed to get VF instance by new VF instance ID: {}", instanceId);
167 resultWrapper.setInnerElement(Either.left(containerComponent));
170 return componentInstance;
174 private List<RequirementCapabilityRelDef> getUpdatedRelations(Stream<RequirementCapabilityRelDef> toRelationsInfoStream,
175 Stream<RequirementCapabilityRelDef> fromRelationsInfoStream) {
176 Stream<RequirementCapabilityRelDef> updatedRelationsStream = Stream.empty();
178 if (toRelationsInfoStream != null) {
179 updatedRelationsStream = Stream.concat(updatedRelationsStream, toRelationsInfoStream);
182 if (fromRelationsInfoStream != null) {
183 updatedRelationsStream = Stream.concat(updatedRelationsStream, fromRelationsInfoStream);
186 return updatedRelationsStream.collect(Collectors.toList());
189 private List<RequirementCapabilityRelDef> getRelations(Function<RequirementCapabilityRelDef, String> getNodeFunc,
190 Component containerComponent,
191 ComponentInstance currentResourceInstance) {
193 final List<RequirementCapabilityRelDef> componentInstancesRelations = containerComponent.getComponentInstancesRelations();
194 if (componentInstancesRelations == null) {
195 return Collections.emptyList();
198 final String vfInstanceId = currentResourceInstance.getUniqueId();
200 return componentInstancesRelations.stream()
201 .filter(rel -> StringUtils.equals(getNodeFunc.apply(rel), vfInstanceId))
202 .collect(Collectors.toList());
205 private List<RelationMergeInfo> convert(List<RequirementCapabilityRelDef> relationsDef,
206 Function<RequirementCapabilityRelDef, RelationMergeInfo> mapFunc) {
207 return relationsDef.stream()
209 .filter(Objects::nonNull)
210 .collect(Collectors.toList());
213 private ContainerRelationsMergeInfo getRelationsMergeInfo(DataForMergeHolder dataHolder,
214 Component updatedContainerComponent,
215 Wrapper<Either<Component, ResponseFormat>> resultWrapper) {
216 ContainerRelationsMergeInfo containerRelationsMergeInfo = dataHolder.getContainerRelationsMergeInfo();
217 if (containerRelationsMergeInfo == null) {
218 log.debug("There is no info about relations should be restored.");
219 resultWrapper.setInnerElement(Either.left(updatedContainerComponent));
222 return containerRelationsMergeInfo;