Added oparent to sdc main
[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.merge.utils.CapabilityOwner;
26 import org.openecomp.sdc.be.components.merge.utils.ComponentInstanceBuildingBlocks;
27 import org.openecomp.sdc.be.components.merge.utils.MergeInstanceUtils;
28 import org.openecomp.sdc.be.dao.utils.MapUtil;
29 import org.openecomp.sdc.be.impl.ComponentsUtils;
30 import org.openecomp.sdc.be.model.Component;
31 import org.openecomp.sdc.be.model.ComponentInstance;
32 import org.openecomp.sdc.be.model.RequirementCapabilityRelDef;
33 import org.openecomp.sdc.be.model.User;
34 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
35 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
36 import org.openecomp.sdc.common.datastructure.Wrapper;
37 import org.openecomp.sdc.common.log.wrappers.Logger;
38 import org.openecomp.sdc.exception.ResponseFormat;
39
40 import java.util.Collections;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Objects;
44 import java.util.function.Function;
45 import java.util.stream.Collectors;
46 import java.util.stream.Stream;
47
48
49 @org.springframework.stereotype.Component("ComponentInstanceRelashionMerge")
50 public class ComponentInstanceRelationMerge implements ComponentInstanceMergeInterface {
51     private static final Logger log = Logger.getLogger(ComponentInstanceRelationMerge.class);
52     
53     private final ComponentsUtils componentsUtils;
54     private final MergeInstanceUtils mergeInstanceUtils;
55     private final ToscaOperationFacade toscaOperationFacade;
56
57     public ComponentInstanceRelationMerge(ComponentsUtils componentsUtils, MergeInstanceUtils mergeInstanceUtils, ToscaOperationFacade toscaOperationFacade) {
58         this.componentsUtils = componentsUtils;
59         this.mergeInstanceUtils = mergeInstanceUtils;
60         this.toscaOperationFacade = toscaOperationFacade;
61     }
62     
63
64     @Override
65     public void saveDataBeforeMerge(DataForMergeHolder dataHolder, Component containerComponent, ComponentInstance currentResourceInstance, Component originComponent) {
66         //All Relationships - container (service) holds info about all relations
67         //Filter by UniqueId in from/to
68         List<RequirementCapabilityRelDef> relationsFrom = getRelations(RequirementCapabilityRelDef::getFromNode,
69                                                                       containerComponent,
70                                                                       currentResourceInstance);
71
72         List<RequirementCapabilityRelDef> relationsTo = getRelations(RequirementCapabilityRelDef::getToNode,
73                                                                     containerComponent,
74                                                                     currentResourceInstance);
75
76         if (!relationsFrom.isEmpty() || !relationsTo.isEmpty()) {
77             ComponentInstanceBuildingBlocks instBuildingBlocks = mergeInstanceUtils.getInstanceAtomicBuildingBlocks(currentResourceInstance, originComponent);
78
79             if  (instBuildingBlocks != null) {
80                 List<RelationMergeInfo> fromRelInfoList = convert(relationsFrom, rel -> mergeInstanceUtils.mapRelationRequirement(rel, instBuildingBlocks.getVfcInstances()));
81                 List<RelationMergeInfo> toRelInfoList = convert(relationsTo, rel -> mergeInstanceUtils.mapRelationCapability(rel, instBuildingBlocks.getCapabilitiesOwners()));
82
83                 // Encapsulate all needed info in one container
84                 ContainerRelationsMergeInfo containerRelationsMergeInfo = new ContainerRelationsMergeInfo(fromRelInfoList, toRelInfoList);
85                 // Save it
86                 dataHolder.setVfRelationsInfo(containerRelationsMergeInfo);
87             }
88         }
89         else {
90             log.debug("No relations relevant to currentResourceInstance {} found in container component", currentResourceInstance);
91         }
92
93     }
94
95
96     @Override
97     public Either<Component, ResponseFormat> mergeDataAfterCreate(User user, DataForMergeHolder dataHolder, Component updatedContainerComponent, String newInstanceId) {
98         Wrapper<Either<Component, ResponseFormat>> resultWrapper = new Wrapper<>();
99
100         ContainerRelationsMergeInfo containerRelationsMergeInfo = getRelationsMergeInfo(dataHolder, updatedContainerComponent, resultWrapper);
101
102         ComponentInstance newComponentInstance = null;
103         if(resultWrapper.isEmpty()) {
104             //Component Instance
105             newComponentInstance = loadComponentInstance(updatedContainerComponent, newInstanceId, resultWrapper);
106         }
107
108         if(resultWrapper.isEmpty() && containerRelationsMergeInfo != null) {
109             // Load VFCI and filter them by name
110             ComponentInstanceBuildingBlocks instanceBuildBlocks = mergeInstanceUtils.getInstanceAtomicBuildingBlocks(newComponentInstance);
111             if(instanceBuildBlocks != null) {
112                 // Process Relationships
113                 Stream<RequirementCapabilityRelDef> toRelationsInfoStream = getCapabilitiesRelationInfoStream(updatedContainerComponent, newInstanceId, containerRelationsMergeInfo, instanceBuildBlocks);
114                 Stream<RequirementCapabilityRelDef> fromRelationsInfoStream = getRequirementRelationsInfoStream(updatedContainerComponent, newInstanceId, containerRelationsMergeInfo, instanceBuildBlocks);
115                 List<RequirementCapabilityRelDef> updatedRelations = getUpdatedRelations(toRelationsInfoStream, fromRelationsInfoStream);
116                 StorageOperationStatus saveResult = toscaOperationFacade.associateResourceInstances(updatedContainerComponent.getUniqueId(), updatedRelations);
117                 if (saveResult == StorageOperationStatus.OK) {
118                     resultWrapper.setInnerElement(Either.left(updatedContainerComponent));
119                 }
120                 else {
121                     log.debug("Failed to associate instances of resource {} status is {}", updatedContainerComponent.getUniqueId(), saveResult);
122                     ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(saveResult), updatedContainerComponent.getUniqueId());
123                     resultWrapper.setInnerElement(Either.right(responseFormat));
124                 }
125             }
126         }
127         return resultWrapper.getInnerElement();
128     }
129
130     private Stream<RequirementCapabilityRelDef> getRequirementRelationsInfoStream(Component updatedContainerComponent, String newInstanceId, ContainerRelationsMergeInfo containerRelationsMergeInfo, ComponentInstanceBuildingBlocks instanceBuildBlocks) {
131         Map<String, ComponentInstance> vfciMap = MapUtil.toMap(instanceBuildBlocks.getVfcInstances(), ComponentInstance::getName, (p1, p2) -> p1);
132         List<RelationMergeInfo> fromRelationsInfo = containerRelationsMergeInfo.getFromRelationsInfo();
133         Stream<RequirementCapabilityRelDef> fromRelationsInfoStream = null;
134         if( fromRelationsInfo != null) {
135             fromRelationsInfoStream = fromRelationsInfo.stream()
136                                         .map(oldReqInfo -> mergeInstanceUtils.restoreRequirementRelation(oldReqInfo, newInstanceId, vfciMap, updatedContainerComponent))
137                                         .filter(Objects::nonNull);
138         }
139         return fromRelationsInfoStream;
140     }
141
142     private Stream<RequirementCapabilityRelDef> getCapabilitiesRelationInfoStream(Component updatedContainerComponent, String newInstanceId, ContainerRelationsMergeInfo containerRelationsMergeInfo, ComponentInstanceBuildingBlocks instanceBuildBlocks) {
143         Map<String, CapabilityOwner> capOwnersByName = MapUtil.toMap(instanceBuildBlocks.getCapabilitiesOwners(), CapabilityOwner::getName, (p1, p2) -> p1);
144         List<RelationMergeInfo> toRelationsInfo = containerRelationsMergeInfo.getToRelationsInfo();
145         Stream<RequirementCapabilityRelDef> toRelationsInfoStream = null;
146         if (toRelationsInfo != null) {
147             toRelationsInfoStream = toRelationsInfo.stream()
148                                     .map(oldCapInfo -> mergeInstanceUtils.restoreCapabilityRelation(oldCapInfo, newInstanceId, capOwnersByName, updatedContainerComponent))
149                                     .filter(Objects::nonNull);
150         }
151         return toRelationsInfoStream;
152     }
153
154     /**
155      * @param containerComponent
156      * @param instanceId
157      * @param resultWrapper
158      * @return
159      */
160     private ComponentInstance loadComponentInstance(Component containerComponent, String instanceId,
161             Wrapper<Either<Component, ResponseFormat>> resultWrapper) {
162         ComponentInstance componentInstance = containerComponent.getComponentInstanceById(instanceId).orElse(null);
163         if (componentInstance == null) {
164             log.debug("Failed to get VF instance by new VF instance ID: {}", instanceId);
165             resultWrapper.setInnerElement(Either.left(containerComponent));
166         }
167
168         return componentInstance;
169     }
170
171
172     private List<RequirementCapabilityRelDef> getUpdatedRelations(Stream<RequirementCapabilityRelDef> toRelationsInfoStream, 
173                                                                   Stream<RequirementCapabilityRelDef> fromRelationsInfoStream) {
174         Stream<RequirementCapabilityRelDef> updatedRelationsStream = Stream.empty();
175
176         if (toRelationsInfoStream != null) {
177             updatedRelationsStream = Stream.concat(updatedRelationsStream, toRelationsInfoStream);
178         }
179
180         if (fromRelationsInfoStream != null) {
181             updatedRelationsStream = Stream.concat(updatedRelationsStream, fromRelationsInfoStream);
182         }
183
184         return updatedRelationsStream.collect(Collectors.toList());
185     }
186
187     private List<RequirementCapabilityRelDef> getRelations(Function<RequirementCapabilityRelDef, String> getNodeFunc,
188                                                            Component containerComponent,
189                                                            ComponentInstance currentResourceInstance) {
190
191         final List<RequirementCapabilityRelDef> componentInstancesRelations = containerComponent.getComponentInstancesRelations();
192         if (componentInstancesRelations == null) {
193             return Collections.emptyList();
194         }
195         
196         final String vfInstanceId = currentResourceInstance.getUniqueId();
197
198         return componentInstancesRelations.stream()
199                                             .filter(rel -> StringUtils.equals(getNodeFunc.apply(rel), vfInstanceId))
200                                             .collect(Collectors.toList());
201     }
202
203     private List<RelationMergeInfo> convert(List<RequirementCapabilityRelDef> relationsDef, 
204                                             Function<RequirementCapabilityRelDef, RelationMergeInfo> mapFunc) {
205         return relationsDef.stream()
206                             .map(mapFunc)
207                             .filter(Objects::nonNull)
208                             .collect(Collectors.toList());
209     }
210     
211     private ContainerRelationsMergeInfo getRelationsMergeInfo(DataForMergeHolder dataHolder,
212                                                               Component updatedContainerComponent,
213                                                               Wrapper<Either<Component, ResponseFormat>> resultWrapper) {
214         ContainerRelationsMergeInfo containerRelationsMergeInfo = dataHolder.getContainerRelationsMergeInfo();
215         if (containerRelationsMergeInfo == null) {
216             log.debug("There is no info about relations should be restored.");
217             resultWrapper.setInnerElement(Either.left(updatedContainerComponent));
218         }
219
220         return containerRelationsMergeInfo;
221     }
222 }