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