Catalog alignment
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / merge / instance / ComponentInstanceRelationMerge.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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  */
20
21 package org.openecomp.sdc.be.components.merge.instance;
22
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;
40
41 import java.util.Collections;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Objects;
45 import java.util.function.Function;
46 import java.util.stream.Collectors;
47 import java.util.stream.Stream;
48
49
50 @org.springframework.stereotype.Component("ComponentInstanceRelashionMerge")
51 public class ComponentInstanceRelationMerge implements ComponentInstanceMergeInterface {
52     private static final Logger log = Logger.getLogger(ComponentInstanceRelationMerge.class);
53     
54     private final ComponentsUtils componentsUtils;
55     private final MergeInstanceUtils mergeInstanceUtils;
56     private final ToscaOperationFacade toscaOperationFacade;
57
58     public ComponentInstanceRelationMerge(ComponentsUtils componentsUtils, MergeInstanceUtils mergeInstanceUtils, ToscaOperationFacade toscaOperationFacade) {
59         this.componentsUtils = componentsUtils;
60         this.mergeInstanceUtils = mergeInstanceUtils;
61         this.toscaOperationFacade = toscaOperationFacade;
62     }
63     
64
65     @Override
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,
70                                                                       containerComponent,
71                                                                       currentResourceInstance);
72
73         List<RequirementCapabilityRelDef> relationsTo = getRelations(RequirementCapabilityRelDef::getToNode,
74                                                                     containerComponent,
75                                                                     currentResourceInstance);
76
77         if (!relationsFrom.isEmpty() || !relationsTo.isEmpty()) {
78             ComponentInstanceBuildingBlocks instBuildingBlocks = mergeInstanceUtils.getInstanceAtomicBuildingBlocks(currentResourceInstance, originComponent);
79
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()));
83
84                 // Encapsulate all needed info in one container
85                 ContainerRelationsMergeInfo containerRelationsMergeInfo = new ContainerRelationsMergeInfo(fromRelInfoList, toRelInfoList);
86                 // Save it
87                 dataHolder.setVfRelationsInfo(containerRelationsMergeInfo);
88             }
89         }
90         else {
91             log.debug("No relations relevant to currentResourceInstance {} found in container component", currentResourceInstance);
92         }
93
94     }
95
96
97     @Override
98     public Component mergeDataAfterCreate(User user, DataForMergeHolder dataHolder, Component updatedContainerComponent, String newInstanceId) {
99         Wrapper<Either<Component, ResponseFormat>> resultWrapper = new Wrapper<>();
100
101         ContainerRelationsMergeInfo containerRelationsMergeInfo = getRelationsMergeInfo(dataHolder, updatedContainerComponent, resultWrapper);
102
103         ComponentInstance newComponentInstance = null;
104         if(resultWrapper.isEmpty()) {
105             //Component Instance
106             newComponentInstance = loadComponentInstance(updatedContainerComponent, newInstanceId, resultWrapper);
107         }
108
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));
120                 }
121                 else {
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);
126                 }
127             }
128         }
129         return resultWrapper.getInnerElement().left().value();
130     }
131
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);
140         }
141         return fromRelationsInfoStream;
142     }
143
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);
152         }
153         return toRelationsInfoStream;
154     }
155
156     /**
157      * @param containerComponent
158      * @param instanceId
159      * @param resultWrapper
160      * @return
161      */
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));
168         }
169
170         return componentInstance;
171     }
172
173
174     private List<RequirementCapabilityRelDef> getUpdatedRelations(Stream<RequirementCapabilityRelDef> toRelationsInfoStream, 
175                                                                   Stream<RequirementCapabilityRelDef> fromRelationsInfoStream) {
176         Stream<RequirementCapabilityRelDef> updatedRelationsStream = Stream.empty();
177
178         if (toRelationsInfoStream != null) {
179             updatedRelationsStream = Stream.concat(updatedRelationsStream, toRelationsInfoStream);
180         }
181
182         if (fromRelationsInfoStream != null) {
183             updatedRelationsStream = Stream.concat(updatedRelationsStream, fromRelationsInfoStream);
184         }
185
186         return updatedRelationsStream.collect(Collectors.toList());
187     }
188
189     private List<RequirementCapabilityRelDef> getRelations(Function<RequirementCapabilityRelDef, String> getNodeFunc,
190                                                            Component containerComponent,
191                                                            ComponentInstance currentResourceInstance) {
192
193         final List<RequirementCapabilityRelDef> componentInstancesRelations = containerComponent.getComponentInstancesRelations();
194         if (componentInstancesRelations == null) {
195             return Collections.emptyList();
196         }
197         
198         final String vfInstanceId = currentResourceInstance.getUniqueId();
199
200         return componentInstancesRelations.stream()
201                                             .filter(rel -> StringUtils.equals(getNodeFunc.apply(rel), vfInstanceId))
202                                             .collect(Collectors.toList());
203     }
204
205     private List<RelationMergeInfo> convert(List<RequirementCapabilityRelDef> relationsDef, 
206                                             Function<RequirementCapabilityRelDef, RelationMergeInfo> mapFunc) {
207         return relationsDef.stream()
208                             .map(mapFunc)
209                             .filter(Objects::nonNull)
210                             .collect(Collectors.toList());
211     }
212     
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));
220         }
221
222         return containerRelationsMergeInfo;
223     }
224 }