Reformat catalog-model
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / jsonjanusgraph / utils / CapabilityRequirementNameResolver.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 package org.openecomp.sdc.be.model.jsonjanusgraph.utils;
21
22 import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
23 import static org.apache.commons.lang3.StringUtils.isBlank;
24
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Objects;
31 import java.util.Optional;
32 import java.util.function.Function;
33 import java.util.stream.Collectors;
34 import org.apache.commons.collections.CollectionUtils;
35 import org.apache.commons.collections.MapUtils;
36 import org.apache.commons.lang3.StringUtils;
37 import org.openecomp.sdc.be.config.BeEcompErrorManager;
38 import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition;
39 import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition;
40 import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition;
41 import org.openecomp.sdc.be.datatypes.elements.MapCapabilityProperty;
42 import org.openecomp.sdc.be.datatypes.elements.MapListCapabilityDataDefinition;
43 import org.openecomp.sdc.be.datatypes.elements.MapPropertiesDataDefinition;
44 import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition;
45 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
46 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.TopologyTemplate;
47 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement;
48 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElementTypeEnum;
49 import org.openecomp.sdc.be.model.utils.ComponentUtilities;
50 import org.openecomp.sdc.common.log.wrappers.Logger;
51
52 public class CapabilityRequirementNameResolver {
53
54     private static final Logger log = Logger.getLogger(CapabilityRequirementNameResolver.class);
55     private static final String PATH_DELIMITER = ".";
56
57     public static void updateNamesOfCalculatedCapabilitiesRequirements(TopologyTemplate toscaElement, String ownerId, String ownerName,
58                                                                        Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
59         Map<String, ToscaElement> componentCacheToRepair = new HashMap<>();
60         log.debug("#updateNamesOfCalculatedCapabilitiesRequirements");
61         updateCalculatedCapabilitiesNames(componentCacheToRepair, toscaElement, ownerId, ownerName, originGetter);
62         updateCalculatedRequirementsNames(componentCacheToRepair, toscaElement, ownerId, ownerName, originGetter);
63         updateCalculatedCapabilitiesPropertiesKeys(toscaElement, ownerId);
64     }
65
66     private static void updateCalculatedCapabilitiesPropertiesKeys(TopologyTemplate toscaElement, String ownerId) {
67         if (calCapPropertiesExist(toscaElement, ownerId)) {
68             MapCapabilityProperty newProps = new MapCapabilityProperty();
69             toscaElement.getCalculatedCapabilitiesProperties().get(ownerId).getMapToscaDataDefinition().forEach(
70                 (k, v) -> updateAndAddCalculatedCapabilitiesProperties(k, v, toscaElement.getCalculatedCapabilities().get(ownerId), newProps));
71             if (MapUtils.isNotEmpty(newProps.getMapToscaDataDefinition())) {
72                 toscaElement.getCalculatedCapabilitiesProperties().put(ownerId, newProps);
73             }
74         }
75     }
76
77     private static boolean calCapPropertiesExist(TopologyTemplate toscaElement, String ownerId) {
78         return toscaElement.getCalculatedCapabilitiesProperties() != null && toscaElement.getCalculatedCapabilitiesProperties().get(ownerId) != null
79             && MapUtils.isNotEmpty(toscaElement.getCalculatedCapabilitiesProperties().get(ownerId).getMapToscaDataDefinition()) && capabilitiesExist(
80             toscaElement, ownerId);
81     }
82
83     private static void updateCalculatedRequirementsNames(Map<String, ToscaElement> componentCacheToRepair, TopologyTemplate toscaElement,
84                                                           String ownerId, String ownerName,
85                                                           Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
86         if (requirementsExist(toscaElement, ownerId)) {
87             String prefix = ownerName + PATH_DELIMITER;
88             repairReqNames(componentCacheToRepair, toscaElement, ownerId, originGetter);
89             toscaElement.getCalculatedRequirements().get(ownerId).getMapToscaDataDefinition().values().stream()
90                 .flatMap(l -> l.getListToscaDataDefinition().stream()).forEach(r -> {
91                 if (isRequiredToRepair(r.getName())) {
92                     BeEcompErrorManager.getInstance().logBeComponentMissingError(
93                         "The empty name of the requirement was found. Id: " + r.getUniqueId() + ", ownerId: " + ownerId + ", ownerName: " + ownerName,
94                         toscaElement.getComponentType().getValue(), toscaElement.getName());
95                 }
96                 if (ComponentUtilities.isNotUpdatedCapReqName(prefix, r.getName(), r.getPreviousName())) {
97                     if (StringUtils.isNotEmpty(r.getPreviousName())) {
98                         r.setParentName(r.getPreviousName());
99                     }
100                     r.setPreviousName(r.getName());
101                 }
102                 r.setName(prefix + r.getPreviousName());
103             });
104         }
105     }
106
107     private static boolean requirementsExist(TopologyTemplate toscaElement, String ownerId) {
108         return toscaElement.getCalculatedRequirements() != null && toscaElement.getCalculatedRequirements().get(ownerId) != null && MapUtils
109             .isNotEmpty(toscaElement.getCalculatedRequirements().get(ownerId).getMapToscaDataDefinition());
110     }
111
112     private static void updateCalculatedCapabilitiesNames(Map<String, ToscaElement> componentCacheToRepair, TopologyTemplate toscaElement,
113                                                           String ownerId, String ownerName,
114                                                           Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
115         if (capabilitiesExist(toscaElement, ownerId)) {
116             String prefix = ownerName + PATH_DELIMITER;
117             repairCapNames(componentCacheToRepair, toscaElement, ownerId, originGetter);
118             toscaElement.getCalculatedCapabilities().get(ownerId).getMapToscaDataDefinition().values().stream()
119                 .flatMap(l -> l.getListToscaDataDefinition().stream()).forEach(c -> {
120                 if (isRequiredToRepair(c.getName())) {
121                     BeEcompErrorManager.getInstance().logBeComponentMissingError(
122                         "The empty name of the capability was found. Id: " + c.getUniqueId() + ", ownerId: " + ownerId + ", ownerName: " + ownerName,
123                         toscaElement.getComponentType().getValue(), toscaElement.getName());
124                 }
125                 if (ComponentUtilities.isNotUpdatedCapReqName(prefix, c.getName(), c.getPreviousName())) {
126                     if (StringUtils.isNotEmpty(c.getPreviousName())) {
127                         c.setParentName(c.getPreviousName());
128                     }
129                     c.setPreviousName(c.getName());
130                 }
131                 c.setName(prefix + c.getPreviousName());
132             });
133         }
134     }
135
136     private static boolean capabilitiesExist(TopologyTemplate toscaElement, String ownerId) {
137         return toscaElement.getCalculatedCapabilities() != null && toscaElement.getCalculatedCapabilities().get(ownerId) != null && MapUtils
138             .isNotEmpty(toscaElement.getCalculatedCapabilities().get(ownerId).getMapToscaDataDefinition());
139     }
140
141     private static void repairCapNames(Map<String, ToscaElement> componentCacheToRepair, TopologyTemplate toscaElement, String ownerId,
142                                        Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
143         log.debug("#repairCapNames");
144         boolean emptyNameFound = toscaElement.getCalculatedCapabilities() != null && toscaElement.getCalculatedCapabilities().get(ownerId) != null
145             && toscaElement.getCalculatedCapabilities().get(ownerId).getMapToscaDataDefinition() != null && toscaElement.getCalculatedCapabilities()
146             .get(ownerId).getMapToscaDataDefinition().values().stream().filter(Objects::nonNull).flatMap(l -> l.getListToscaDataDefinition().stream())
147             .filter(Objects::nonNull).anyMatch(c -> isRequiredToRepair(c.getName()));
148         ComponentInstanceDataDefinition instance =
149             toscaElement.getComponentInstances() != null ? toscaElement.getComponentInstances().get(ownerId) : null;
150         if (instance != null && emptyNameFound) {
151             log.debug("#repairCapNames - Going to repair the name of the capability for the owner {}. ", ownerId);
152             toscaElement.getCalculatedCapabilities().get(ownerId).getMapToscaDataDefinition().values().stream()
153                 .flatMap(l -> l.getListToscaDataDefinition().stream()).forEach(c -> repairCapName(componentCacheToRepair, instance, c, originGetter));
154         }
155     }
156
157     private static void repairReqNames(Map<String, ToscaElement> componentCacheToRepair, TopologyTemplate toscaElement, String ownerId,
158                                        Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
159         log.debug("#repairReqNames");
160         boolean emptyNameFound = toscaElement.getCalculatedRequirements() != null && toscaElement.getCalculatedRequirements().get(ownerId) != null
161             && toscaElement.getCalculatedRequirements().get(ownerId).getMapToscaDataDefinition() != null && toscaElement.getCalculatedRequirements()
162             .get(ownerId).getMapToscaDataDefinition().values().stream().filter(Objects::nonNull).flatMap(l -> l.getListToscaDataDefinition().stream())
163             .filter(Objects::nonNull).anyMatch(r -> isRequiredToRepair(r.getName()));
164         ComponentInstanceDataDefinition instance =
165             toscaElement.getComponentInstances() != null ? toscaElement.getComponentInstances().get(ownerId) : null;
166         if (instance != null && emptyNameFound) {
167             log.debug("#repairReqNames - Going to repair the name of the requirement for the owner {}. ", ownerId);
168             toscaElement.getCalculatedRequirements().get(ownerId).getMapToscaDataDefinition().values().stream()
169                 .flatMap(l -> l.getListToscaDataDefinition().stream()).forEach(r -> repairReqName(componentCacheToRepair, instance, r, originGetter));
170         }
171     }
172
173     private static void repairCapName(Map<String, ToscaElement> componentCacheToRepair, ComponentInstanceDataDefinition instance,
174                                       CapabilityDataDefinition capability, Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
175         if (isRequiredToRepair(capability.getName())) {
176             log.debug("#repairTopologyTemplateCapName - Going to build the name for the capability: ", capability.getUniqueId());
177             buildSetCapName(componentCacheToRepair, capability, instance, originGetter);
178         }
179     }
180
181     private static boolean isRequiredToRepair(String name) {
182         boolean isRequiredToRepair = StringUtils.isEmpty(name) || name.endsWith(".null") || name.contains(".null.");
183         if (isRequiredToRepair) {
184             log.debug("#isRequiredToRepair - The name {} should be repaired. ", name);
185         } else {
186             log.debug("#isRequiredToRepair - The name {} should not be repaired. ", name);
187         }
188         return isRequiredToRepair;
189     }
190
191     private static void repairReqName(Map<String, ToscaElement> componentCacheToRepair, ComponentInstanceDataDefinition instance,
192                                       RequirementDataDefinition requirement, Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
193         if (isRequiredToRepair(requirement.getName())) {
194             log.debug("#repairTopologyTemplateCapName - Going to build the name for the requirement: ", requirement.getUniqueId());
195             buildSetReqName(componentCacheToRepair, requirement, instance, originGetter);
196         }
197     }
198
199     private static void updateAndAddCalculatedCapabilitiesProperties(String stringKey, MapPropertiesDataDefinition properties,
200                                                                      MapListCapabilityDataDefinition calculatedCapabilities,
201                                                                      MapCapabilityProperty newProps) {
202         String[] key = stringKey.split(ModelConverter.CAP_PROP_DELIM);
203         String capType = key[key.length - 2];
204         String capName = key[key.length - 1];
205         Optional<CapabilityDataDefinition> foundCapOpt = calculatedCapabilities.getMapToscaDataDefinition().get(capType).getListToscaDataDefinition()
206             .stream().filter(c -> StringUtils.isNotEmpty(c.getPreviousName()) && c.getPreviousName().equals(capName)).findFirst();
207         foundCapOpt.ifPresent(capabilityDataDefinition -> key[key.length - 1] = capabilityDataDefinition.getName());
208         newProps.put(buildCaLCapPropKey(key), properties);
209     }
210
211     public static void revertNamesOfCalculatedCapabilitiesRequirements(TopologyTemplate toscaElement, String ownerId,
212                                                                        Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
213         Map<String, ToscaElement> componentCacheToRepair = new HashMap<>();
214         log.debug("#revertNamesOfCalculatedCapabilitiesRequirements");
215         revertCalculatedCapabilitiesPropertiesKeys(componentCacheToRepair, toscaElement, ownerId, originGetter);
216         revertCalculatedCapabilitiesNames(toscaElement, ownerId);
217         revertCalculatedRequirementsNames(componentCacheToRepair, toscaElement, ownerId, originGetter);
218     }
219
220     private static void revertCalculatedCapabilitiesPropertiesKeys(Map<String, ToscaElement> componentCacheToRepair, TopologyTemplate toscaElement,
221                                                                    String ownerId,
222                                                                    Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
223         repairCapNames(componentCacheToRepair, toscaElement, ownerId, originGetter);
224         if (calCapPropertiesExist(toscaElement, ownerId)) {
225             MapCapabilityProperty newProps = new MapCapabilityProperty();
226             toscaElement.getCalculatedCapabilitiesProperties().get(ownerId).getMapToscaDataDefinition().forEach(
227                 (k, v) -> revertAndAddCalculatedCapabilitiesProperties(k, v, toscaElement.getCalculatedCapabilities().get(ownerId), newProps));
228             if (MapUtils.isNotEmpty(newProps.getMapToscaDataDefinition())) {
229                 toscaElement.getCalculatedCapabilitiesProperties().put(ownerId, newProps);
230             }
231         }
232     }
233
234     private static void revertCalculatedRequirementsNames(Map<String, ToscaElement> componentCacheToRepair, TopologyTemplate toscaElement,
235                                                           String ownerId, Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
236         repairReqNames(componentCacheToRepair, toscaElement, ownerId, originGetter);
237         if (requirementsExist(toscaElement, ownerId)) {
238             toscaElement.getCalculatedRequirements().get(ownerId).getMapToscaDataDefinition().values().stream()
239                 .flatMap(l -> l.getListToscaDataDefinition().stream()).forEach(CapabilityRequirementNameResolver::revertReqNames);
240         }
241     }
242
243     private static void revertReqNames(RequirementDataDefinition requirement) {
244         if (StringUtils.isNotEmpty(requirement.getPreviousName())) {
245             requirement.setName(requirement.getPreviousName());
246             requirement.setPreviousName(requirement.getParentName());
247         }
248     }
249
250     private static void revertCalculatedCapabilitiesNames(TopologyTemplate toscaElement, String ownerId) {
251         if (capabilitiesExist(toscaElement, ownerId)) {
252             toscaElement.getCalculatedCapabilities().get(ownerId).getMapToscaDataDefinition().values().stream()
253                 .flatMap(l -> l.getListToscaDataDefinition().stream()).forEach(CapabilityRequirementNameResolver::revertCapNames);
254         }
255     }
256
257     private static void revertCapNames(CapabilityDataDefinition capability) {
258         if (StringUtils.isNotEmpty(capability.getPreviousName())) {
259             capability.setName(capability.getPreviousName());
260             capability.setPreviousName(capability.getParentName());
261         }
262     }
263
264     private static void revertAndAddCalculatedCapabilitiesProperties(String stringKey, MapPropertiesDataDefinition properties,
265                                                                      MapListCapabilityDataDefinition calculatedCapabilities,
266                                                                      MapCapabilityProperty newProps) {
267         String[] key = stringKey.split(ModelConverter.CAP_PROP_DELIM);
268         String capType = key[key.length - 2];
269         String capName = key[key.length - 1];
270         Optional<CapabilityDataDefinition> foundCapOpt = calculatedCapabilities.getMapToscaDataDefinition().get(capType).getListToscaDataDefinition()
271             .stream().filter(c -> c.getName().equals(capName) && StringUtils.isNotEmpty(c.getPreviousName())).findFirst();
272         foundCapOpt.ifPresent(capabilityDataDefinition -> key[key.length - 1] = capabilityDataDefinition.getPreviousName());
273         newProps.put(buildCaLCapPropKey(key), properties);
274     }
275
276     private static String buildCaLCapPropKey(String[] keyArray) {
277         StringBuilder key = new StringBuilder();
278         for (int i = 0; i < keyArray.length; ++i) {
279             key.append(keyArray[i]);
280             if (i < keyArray.length - 1) {
281                 key.append(ModelConverter.CAP_PROP_DELIM);
282             }
283         }
284         return key.toString();
285     }
286
287     private static void buildSetCapName(Map<String, ToscaElement> componentsCache, CapabilityDataDefinition capability,
288                                         ComponentInstanceDataDefinition instance,
289                                         Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
290         List<String> reducedPath = capability.getOwnerId() != null ? getReducedPathByOwner(capability.getPath(), capability.getOwnerId())
291             : getReducedPath(capability.getPath());
292         log.debug("reducedPath for ownerId {}, reducedPath {} ", capability.getOwnerId(), reducedPath);
293         reducedPath.remove(reducedPath.size() - 1);
294         ToscaElement originComponent = getOriginComponent(componentsCache, instance, originGetter);
295         String name = isRequiredToRepair(capability.getParentName()) ? extractNameFromUniqueId(capability.getUniqueId()) : capability.getParentName();
296         StringBuilder repairedName = buildSubstitutedName(componentsCache, originComponent, reducedPath, originGetter);
297         log.debug("#buildSetCapName - The name for the capability was built: {}", repairedName);
298         capability.setName(repairedName.append(name).toString());
299         if (isRequiredToRepair(capability.getPreviousName())) {
300             capability.setPreviousName(capability.getName().substring(capability.getName().indexOf(PATH_DELIMITER) + 1));
301         }
302         if (isRequiredToRepair(capability.getParentName())) {
303             capability.setParentName(name);
304         }
305     }
306
307     private static void buildSetReqName(Map<String, ToscaElement> componentsCache, RequirementDataDefinition requirement,
308                                         ComponentInstanceDataDefinition instance,
309                                         Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
310         List<String> reducedPath = requirement.getOwnerId() != null ? getReducedPathByOwner(requirement.getPath(), requirement.getOwnerId())
311             : getReducedPath(requirement.getPath());
312         log.debug("reducedPath for ownerId {}, reducedPath {} ", requirement.getOwnerId(), reducedPath);
313         reducedPath.remove(reducedPath.size() - 1);
314         ToscaElement originComponent = getOriginComponent(componentsCache, instance, originGetter);
315         String name =
316             isRequiredToRepair(requirement.getParentName()) ? extractNameFromUniqueId(requirement.getUniqueId()) : requirement.getParentName();
317         StringBuilder repairedName = buildSubstitutedName(componentsCache, originComponent, reducedPath, originGetter);
318         log.debug("#buildSetReqName - The name for the capability was built: ", repairedName);
319         requirement.setName(repairedName.append(name).toString());
320         if (isRequiredToRepair(requirement.getPreviousName())) {
321             requirement.setPreviousName(requirement.getName().substring(requirement.getName().indexOf(PATH_DELIMITER) + 1));
322         }
323         if (isRequiredToRepair(requirement.getParentName())) {
324             requirement.setParentName(name);
325         }
326     }
327
328     private static String extractNameFromUniqueId(String uniqueId) {
329         String[] uid = uniqueId.split("\\.");
330         return uid[uid.length - 1];
331     }
332
333     private static StringBuilder buildSubstitutedName(Map<String, ToscaElement> componentsCache, ToscaElement originComponent, List<String> path,
334                                                       Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
335         StringBuilder substitutedName = new StringBuilder();
336         log.debug("#buildSubstitutedName");
337         if (isNotEmpty(path) && isTopologyTemplateNotCvfc(originComponent)) {
338             log.debug("#buildSubstitutedName");
339             List<String> reducedPath = getReducedPath(path);
340             Collections.reverse(reducedPath);
341             appendNameRecursively(componentsCache, originComponent, reducedPath.iterator(), substitutedName, originGetter);
342         }
343         return substitutedName;
344     }
345
346     private static boolean isTopologyTemplateNotCvfc(ToscaElement originComponent) {
347         return originComponent.getToscaType() == ToscaElementTypeEnum.TOPOLOGY_TEMPLATE && originComponent.getResourceType() != ResourceTypeEnum.CVFC;
348     }
349
350     private static ToscaElement getOriginComponent(Map<String, ToscaElement> componentsCache, ComponentInstanceDataDefinition instance,
351                                                    Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
352         if (componentsCache.containsKey(getActualComponentUid(instance))) {
353             return componentsCache.get(getActualComponentUid(instance));
354         }
355         ToscaElement origin = originGetter.apply(instance);
356         componentsCache.put(origin.getUniqueId(), origin);
357         return origin;
358     }
359
360     public static String getActualComponentUid(ComponentInstanceDataDefinition instance) {
361         return instance.getIsProxy() ? instance.getSourceModelUid() : instance.getComponentUid();
362     }
363
364     private static List<String> getReducedPath(List<String> path) {
365         return path.stream().distinct().collect(Collectors.toList());
366     }
367
368     private static void appendNameRecursively(Map<String, ToscaElement> componentsCache, ToscaElement originComponent,
369                                               Iterator<String> instanceIdIter, StringBuilder substitutedName,
370                                               Function<ComponentInstanceDataDefinition, ToscaElement> originGetter) {
371         log.debug("#appendNameRecursively");
372         if (isTopologyTemplateNotCvfc(originComponent) && MapUtils.isNotEmpty(((TopologyTemplate) originComponent).getComponentInstances())
373             && instanceIdIter.hasNext()) {
374             String ownerId = instanceIdIter.next();
375             Optional<ComponentInstanceDataDefinition> instanceOpt = ((TopologyTemplate) originComponent).getComponentInstances().values().stream()
376                 .filter(i -> i.getUniqueId().equals(ownerId)).findFirst();
377             if (instanceOpt.isPresent()) {
378                 substitutedName.append(instanceOpt.get().getNormalizedName()).append(PATH_DELIMITER);
379                 ToscaElement getOriginRes = getOriginComponent(componentsCache, instanceOpt.get(), originGetter);
380                 appendNameRecursively(componentsCache, getOriginRes, instanceIdIter, substitutedName, originGetter);
381             } else if (MapUtils.isNotEmpty(((TopologyTemplate) originComponent).getGroups())) {
382                 Optional<GroupDataDefinition> groupOpt = ((TopologyTemplate) originComponent).getGroups().values().stream()
383                     .filter(g -> g.getUniqueId().equals(ownerId)).findFirst();
384                 groupOpt.ifPresent(groupDataDefinition -> substitutedName.append(groupDataDefinition.getName()).append(PATH_DELIMITER));
385             } else {
386                 log.debug("Failed to find an capability owner with uniqueId {} on a component with uniqueId {}", ownerId,
387                     originComponent.getUniqueId());
388             }
389         }
390     }
391
392     private static List<String> getReducedPathByOwner(List<String> path, String ownerId) {
393         log.debug("ownerId {}, path {} ", ownerId, path);
394         if (CollectionUtils.isEmpty(path)) {
395             log.debug("cannot perform reduce by owner, path to component is empty");
396             return path;
397         }
398         if (isBlank(ownerId)) {
399             log.debug("cannot perform reduce by owner, component owner is empty");
400             return path;
401         }
402         //reduce by owner
403         Map map = path.stream()
404             .collect(Collectors.toMap(it -> dropLast(it, PATH_DELIMITER), Function.identity(), (a, b) -> a.endsWith(ownerId) ? a : b));
405         //reduce list&duplicates and preserve order
406         return path.stream().distinct().filter(it -> map.values().contains(it)).collect(Collectors.toList());
407     }
408
409     private static String dropLast(String path, String delimiter) {
410         if (isBlank(path) || isBlank(delimiter)) {
411             return path;
412         }
413         return path.substring(0, path.lastIndexOf(delimiter));
414     }
415 }