/*- * ============LICENSE_START======================================================= * SDC * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============LICENSE_END========================================================= */ package org.openecomp.sdc.be.tosca; import static org.apache.commons.collections.CollectionUtils.isNotEmpty; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNoneBlank; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import fj.data.Either; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstance; import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.ComponentParametersView; import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.GroupDefinition; import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.RequirementDefinition; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.utils.ComponentUtilities; import org.openecomp.sdc.be.tosca.ToscaUtils.SubstitutionEntry; import org.openecomp.sdc.be.tosca.model.ToscaCapability; import org.openecomp.sdc.be.tosca.model.ToscaNodeTemplate; import org.openecomp.sdc.be.tosca.model.ToscaNodeType; import org.openecomp.sdc.be.tosca.model.ToscaProperty; import org.openecomp.sdc.be.tosca.model.ToscaRequirement; import org.openecomp.sdc.be.tosca.model.ToscaTemplateCapability; import org.openecomp.sdc.common.log.wrappers.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; /** * Allows to convert requirements\capabilities of a component to requirements\capabilities of a substitution mappings section of a tosca template */ @org.springframework.stereotype.Component("capabilty-requirement-convertor") @Scope(value = "singleton") public class CapabilityRequirementConverter { private static final String NO_CAPABILITIES = "No Capabilities for node type"; private static final String NO_REQUIREMENTS = "No Requirements for node type"; private static final Logger logger = Logger.getLogger(CapabilityRequirementConverter.class); private static final String PATH_DELIMITER = "."; private static final String FAILED_TO_FIND_CI_IN_PATH = "Failed to find ci in the path is {} component {}"; private static CapabilityRequirementConverter instance; @Autowired private ToscaOperationFacade toscaOperationFacade; @Autowired private PropertyConvertor propertyConvertor; public CapabilityRequirementConverter() { } public static synchronized CapabilityRequirementConverter getInstance() { if (instance == null) { instance = new CapabilityRequirementConverter(); } return instance; } public String buildCapabilityNameForComponentInstance(Map componentCache, ComponentInstance componentInstance, CapabilityDefinition c) { String prefix = buildCapReqNamePrefix(componentInstance.getNormalizedName()); if (ComponentUtilities.isNotUpdatedCapReqName(prefix, c.getName(), c.getPreviousName())) { return buildSubstitutedName(componentCache, c.getName(), c.getPreviousName(), c.getPath(), c.getOwnerId(), componentInstance).left() .orValue(c.getName()); } return c.getPreviousName(); } public String buildRequirementNameForComponentInstance(Map componentCache, ComponentInstance componentInstance, RequirementDefinition r) { String prefix = buildCapReqNamePrefix(componentInstance.getNormalizedName()); if (ComponentUtilities.isNotUpdatedCapReqName(prefix, r.getName(), r.getPreviousName())) { return buildSubstitutedName(componentCache, r.getName(), r.getPreviousName(), r.getPath(), r.getOwnerId(), componentInstance).left() .orValue(r.getName()); } return r.getPreviousName(); } private String buildCapReqNamePrefix(String normalizedName) { return normalizedName + PATH_DELIMITER; } /** * Allows to convert capabilities of a component to capabilities of a substitution mappings section of a tosca template * * @param componentInstance * @param dataTypes * @param nodeTemplate * @return */ public Either convertComponentInstanceCapabilities(ComponentInstance componentInstance, Map dataTypes, ToscaNodeTemplate nodeTemplate) { Map> capabilitiesInst = componentInstance.getCapabilities(); Map componentCache = new HashMap<>(); if (capabilitiesInst != null && !capabilitiesInst.isEmpty()) { Map capabilities = new HashMap<>(); capabilitiesInst.entrySet().forEach(e -> { List capList = e.getValue(); if (capList != null && !capList.isEmpty()) { capList.stream().forEach(c -> convertOverridenProperties(componentInstance, dataTypes, capabilities, c, buildCapabilityNameForComponentInstance(componentCache, componentInstance, c))); } }); if (MapUtils.isNotEmpty(capabilities)) { nodeTemplate.setCapabilities(capabilities); } } return Either.left(nodeTemplate); } private void convertOverridenProperties(ComponentInstance componentInstance, Map dataTypes, Map capabilties, CapabilityDefinition c, String capabilityName) { if (isNotEmpty(c.getProperties())) { c.getProperties().stream().filter(p -> p.getValue() != null || p.getDefaultValue() != null) .forEach(p -> convertOverriddenProperty(componentInstance, dataTypes, capabilties, p, capabilityName)); } } private void convertOverriddenProperty(ComponentInstance componentInstance, Map dataTypes, Map capabilties, ComponentInstanceProperty p, String capabilityName) { if (logger.isDebugEnabled()) { logger.debug("Exist d property {} for capability {} with value {}", p.getName(), capabilityName, p.getValue()); } ToscaTemplateCapability toscaTemplateCapability = capabilties.computeIfAbsent(capabilityName, key -> new ToscaTemplateCapability()); Map toscaCapProp = toscaTemplateCapability.getProperties(); if (toscaCapProp == null) { toscaCapProp = new HashMap<>(); } Object convertedValue = convertInstanceProperty(dataTypes, componentInstance, p); toscaCapProp.put(p.getName(), convertedValue); toscaTemplateCapability.setProperties(toscaCapProp); } private Object convertInstanceProperty(Map dataTypes, ComponentInstance componentInstance, ComponentInstanceProperty prop) { logger.debug("Convert property {} for instance {}", prop.getName(), componentInstance.getUniqueId()); String propValue = prop.getValue() == null ? prop.getDefaultValue() : prop.getValue(); return propertyConvertor.convertToToscaObject(prop, propValue, dataTypes, false); } /** * Allows to convert requirements of a node type to tosca template requirements representation * * @param component * @param nodeType * @return */ public Either convertRequirements(Map componentsCache, Component component, ToscaNodeType nodeType) { List> toscaRequirements = convertRequirementsAsList(componentsCache, component); if (!toscaRequirements.isEmpty()) { nodeType.setRequirements(toscaRequirements); } logger.debug("Finish convert Requirements for node type"); return Either.left(nodeType); } /** * Allows to convert component requirements to the tosca template substitution mappings requirements * * @param component * @param componentsCache * @return */ public Either, ToscaError> convertSubstitutionMappingRequirements(final Component component, final Map componentsCache) { Either, ToscaError> toscaRequirementsRes = convertSubstitutionMappingRequirementsAsMap(componentsCache, component); if (toscaRequirementsRes.isRight()) { logger.debug("Failed convert requirements for the component {}. ", component.getName()); return Either.right(toscaRequirementsRes.right().value()); } if (MapUtils.isNotEmpty(toscaRequirementsRes.left().value())) { logger.debug("Finish convert requirements for the component {}. ", component.getName()); return Either.left(toscaRequirementsRes.left().value()); } return Either.left(Collections.emptyMap()); } /** * Allows to convert requirements of a server proxy node type to tosca template requirements * * @param instanceProxy * @return converted tosca template requirements */ List> convertProxyRequirements(Map componentCache, ComponentInstance instanceProxy) { Map> requirements = instanceProxy.getRequirements(); List> toscaRequirements = new ArrayList<>(); if (requirements != null) { requirements.entrySet().stream().flatMap(e -> e.getValue().stream()).forEach(req -> { ImmutablePair pair = convertProxyRequirement( buildRequirementNameForComponentInstance(componentCache, instanceProxy, req), req); Map requirement = new HashMap<>(); requirement.put(pair.left, pair.right); toscaRequirements.add(requirement); }); } else { logger.debug(NO_REQUIREMENTS); } return toscaRequirements; } private ImmutablePair convertProxyRequirement(String requirementName, RequirementDefinition r) { ToscaRequirement toscaRequirement = createToscaRequirement(r); return new ImmutablePair<>(requirementName, toscaRequirement); } private List> convertRequirementsAsList(Map componentsCache, Component component) { Map> requirements = component.getRequirements(); List> toscaRequirements = new ArrayList<>(); if (requirements != null) { for (Map.Entry> entry : requirements.entrySet()) { entry.getValue().stream().filter(r -> filter(component, r.getOwnerId())).forEach(r -> { ImmutablePair pair = convertRequirement(componentsCache, component, ModelConverter.isAtomicComponent(component), r); Map requirement = new HashMap<>(); requirement.put(pair.left, pair.right); toscaRequirements.add(requirement); }); logger.debug("Finish convert Requirements for node type"); } } else { logger.debug(NO_REQUIREMENTS); } return toscaRequirements; } private boolean filter(Component component, String ownerId) { return !ModelConverter.isAtomicComponent(component) || isNodeTypeOwner(component, ownerId) || (ModelConverter.isAtomicComponent(component) && ownerId == null); } private boolean isNodeTypeOwner(Component component, String ownerId) { return ModelConverter.isAtomicComponent(component) && component.getUniqueId().equals(ownerId); } private String dropLast(String path, String delimiter) { if (isBlank(path) || isBlank(delimiter)) { return path; } return path.substring(0, path.lastIndexOf(delimiter)); } private Either, ToscaError> convertSubstitutionMappingRequirementsAsMap(Map componentsCache, Component component) { Map> requirements = component.getRequirements(); Either, ToscaError> result; if (requirements != null) { result = buildAddSubstitutionMappingsRequirements(componentsCache, component, requirements); } else { result = Either.left(Maps.newHashMap()); logger.debug("No requirements for substitution mappings section of a tosca template of the component {}. ", component.getName()); } return result; } private Either, ToscaError> buildAddSubstitutionMappingsRequirements(Map componentsCache, Component component, Map> requirements) { Map toscaRequirements = new HashMap<>(); Either, ToscaError> result = null; for (Map.Entry> entry : requirements.entrySet()) { Optional failedToAddRequirement = addExternalToToscaRequirements(componentsCache, toscaRequirements, component, entry.getValue()); if (failedToAddRequirement.isPresent()) { logger.debug("Failed to convert requirement {} for substitution mappings section of a tosca template of the component {}. ", failedToAddRequirement.get().getName(), component.getName()); result = Either.right(ToscaError.NODE_TYPE_REQUIREMENT_ERROR); } logger.debug("Finish convert requirements for the component {}. ", component.getName()); } if (result == null) { result = Either.left(toscaRequirements); } return result; } private Optional addExternalToToscaRequirements(final Map componentsCache, final Map toscaRequirements, final Component component, final List requirements) { return requirements.stream().filter(RequirementDefinition::isExternal).filter( r -> ! (StringUtils.isEmpty(r.getExternalName()) ? addEntry(componentsCache, toscaRequirements, component, new SubstitutionEntry(r.getName(), r.getParentName(), ""), r.getPreviousName(), r.getOwnerId(), r.getPath()): addEntry(componentsCache, toscaRequirements, component, new SubstitutionEntry(r.getExternalName(), r.getPreviousName() == null ? r.getName(): r.getPreviousName(), ""), r.getPreviousName(), r.getOwnerId(), r.getPath(), false)) ).findAny(); } private Either, ToscaError> buildAddSubstitutionMappingsCapabilities(Map componentsCache, Component component, Map> capabilities) { Map toscaCapabilities = new HashMap<>(); Either, ToscaError> result = null; for (Map.Entry> entry : capabilities.entrySet()) { Optional failedToAddRequirement = addExternalToToscaCapabilities(componentsCache, toscaCapabilities, component, entry.getValue()); if (failedToAddRequirement.isPresent()) { logger.debug("Failed to convert capability {} for substitution mappings section of a tosca template of the component {}. ", failedToAddRequirement.get().getName(), component.getName()); result = Either.right(ToscaError.NODE_TYPE_CAPABILITY_ERROR); } logger.debug("Finish convert capabilities for the component {}. ", component.getName()); } if (result == null) { result = Either.left(toscaCapabilities); } return result; } private Optional addExternalToToscaCapabilities(final Map componentsCache, final Map toscaCapabilities, final Component component, final List requirements) { return requirements.stream() .filter(CapabilityDataDefinition::isExternal) .filter( c -> ! (StringUtils.isEmpty(c.getExternalName()) ? addEntry(componentsCache, toscaCapabilities, component, new SubstitutionEntry(c.getName(), c.getParentName(), ""), c.getPreviousName(), c.getOwnerId(), c.getPath()): addEntry(componentsCache, toscaCapabilities, component, new SubstitutionEntry(c.getName(), c.getParentName(), ""), c.getPreviousName(), c.getOwnerId(), c.getPath(), false)) ).findAny(); } private boolean addEntry(Map componentsCache, Map capReqMap, Component component, SubstitutionEntry entry, String previousName, String ownerId, List path) { return addEntry(componentsCache, capReqMap, component, entry, previousName, ownerId, path, shouldBuildSubstitutionName(component, path)); } private boolean addEntry(final Map componentsCache, Map capReqMap, final Component component, final SubstitutionEntry entry, final String previousName, final String ownerId, final List path, final boolean shouldBuildSubstitutionName) { if (shouldBuildSubstitutionName && !buildSubstitutedNamePerInstance(componentsCache, component, entry.getFullName(), previousName, path, ownerId, entry)) { return false; } logger.debug("The requirement/capability {} belongs to the component {} ", entry.getFullName(), component.getUniqueId()); if (StringUtils.isNotEmpty(entry.getSourceName())) { addEntry(capReqMap, component, path, entry); } logger.debug("Finish convert the requirement/capability {} for the component {}. ", entry.getFullName(), component.getName()); return true; } private boolean shouldBuildSubstitutionName(Component component, List path) { return ToscaUtils.isNotComplexVfc(component) && isNotEmpty(path) && path.iterator().hasNext(); } private boolean buildSubstitutedNamePerInstance(Map componentsCache, Component component, String name, String previousName, List path, String ownerId, SubstitutionEntry entry) { String fullName; String sourceName; String prefix; if (CollectionUtils.isNotEmpty(component.getGroups())) { Optional groupOpt = component.getGroups().stream().filter(g -> g.getUniqueId().equals(ownerId)).findFirst(); if (groupOpt.isPresent()) { prefix = buildCapReqNamePrefix(groupOpt.get().getNormalizedName()); if (ComponentUtilities.isNotUpdatedCapReqName(prefix, name, previousName)) { sourceName = name; fullName = prefix + sourceName; } else { sourceName = previousName; fullName = name; } entry.setFullName(fullName); entry.setSourceName(sourceName); entry.setOwner(groupOpt.get().getNormalizedName()); return true; } } Optional ci = component.safeGetComponentInstances().stream().filter(c -> c.getUniqueId().equals(Iterables.getLast(path))) .findFirst(); if (!ci.isPresent()) { logger.debug(FAILED_TO_FIND_CI_IN_PATH, path, component.getUniqueId()); Collections.reverse(path); logger.debug("try to reverse path {} component {}", path, component.getUniqueId()); ci = component.safeGetComponentInstances().stream().filter(c -> c.getUniqueId().equals(Iterables.getLast(path))).findFirst(); } if (ci.isPresent()) { prefix = buildCapReqNamePrefix(ci.get().getNormalizedName()); if (ComponentUtilities.isNotUpdatedCapReqName(prefix, name, previousName)) { Either buildSubstitutedName = buildSubstitutedName(componentsCache, name, previousName, path, ownerId, ci.get()); if (buildSubstitutedName.isRight()) { logger.debug("Failed buildSubstitutedName name {} path {} component {}", name, path, component.getUniqueId()); return false; } sourceName = buildSubstitutedName.left().value(); fullName = prefix + sourceName; } else { sourceName = previousName; fullName = name; } entry.setFullName(fullName); entry.setSourceName(sourceName); } else { logger.debug(FAILED_TO_FIND_CI_IN_PATH, path, component.getUniqueId()); return false; } return true; } private void addEntry(Map toscaRequirements, Component component, List capPath, SubstitutionEntry entry) { Optional findFirst = component.safeGetComponentInstances().stream() .filter(ci -> ci.getUniqueId().equals(Iterables.getLast(capPath))).findFirst(); findFirst.ifPresent(componentInstance -> entry.setOwner(componentInstance.getName())); if (StringUtils.isNotEmpty(entry.getOwner()) && StringUtils.isNotEmpty(entry.getSourceName())) { toscaRequirements.put(entry.getFullName(), new String[]{entry.getOwner(), entry.getSourceName()}); } } public Either buildSubstitutedName(Map componentsCache, String name, String previousName, List path, String ownerId, ComponentInstance instance) { if (StringUtils.isNotEmpty(previousName)) { return Either.left(name); } Either getOriginRes = getOriginComponent(componentsCache, instance); if (getOriginRes.isRight()) { logger .debug("Failed to build substituted name for the capability/requirement {}. Failed to get an origin component with uniqueId {}", name, instance.getComponentUid()); return Either.right(false); } List reducedPath = ownerId != null ? getReducedPathByOwner(path, ownerId) : getReducedPath(path); logger.debug("reducedPath for ownerId {}, reducedPath {} ", ownerId, reducedPath); reducedPath.remove(reducedPath.size() - 1); return buildSubstitutedName(componentsCache, getOriginRes.left().value(), reducedPath, name, previousName); } private String buildReqNamePerOwnerByPath(Map componentsCache, Component component, RequirementDefinition r) { return buildCapReqNamePerOwnerByPath(componentsCache, component, r.getName(), r.getPreviousName(), r.getPath()); } private ImmutablePair convertRequirement(Map componentsCache, Component component, boolean isNodeType, RequirementDefinition r) { String name; if (StringUtils.isEmpty(r.getExternalName())){ name = r.getName(); if (!isNodeType && ToscaUtils.isNotComplexVfc(component)) { name = buildReqNamePerOwnerByPath(componentsCache, component, r); } } else { name = r.getExternalName(); } logger.debug("the requirement {} belongs to resource {} ", name, component.getUniqueId()); ToscaRequirement toscaRequirement = createToscaRequirement(r); return new ImmutablePair<>(name, toscaRequirement); } private ToscaRequirement createToscaRequirement(RequirementDefinition r) { ToscaRequirement toscaRequirement = new ToscaRequirement(); List occurrences = new ArrayList<>(); occurrences.add(Integer.valueOf(r.getMinOccurrences())); if (r.getMaxOccurrences().equals(RequirementDataDefinition.MAX_OCCURRENCES)) { occurrences.add(r.getMaxOccurrences()); } else { occurrences.add(Integer.valueOf(r.getMaxOccurrences())); } toscaRequirement.setOccurrences(occurrences); toscaRequirement.setNode(r.getNode()); toscaRequirement.setCapability(r.getCapability()); toscaRequirement.setRelationship(r.getRelationship()); return toscaRequirement; } /** * Allows to convert capabilities of a node type to tosca template capabilities * * @param component * @param dataTypes * @return */ public Map convertCapabilities(Map componentsCache, Component component, Map dataTypes) { Map> capabilities = component.getCapabilities(); Map toscaCapabilities = new HashMap<>(); if (capabilities != null) { boolean isNodeType = ModelConverter.isAtomicComponent(component); for (Map.Entry> entry : capabilities.entrySet()) { entry.getValue().stream().filter(c -> filter(component, c.getOwnerId())) .forEach(c -> convertCapability(componentsCache, component, toscaCapabilities, isNodeType, c, dataTypes, c.getName())); } } else { logger.debug(NO_CAPABILITIES); } return toscaCapabilities; } /** * Allows to convert capabilities of a server proxy node type to tosca template capabilities * * @param instanceProxy * @param dataTypes * @return */ public Map convertProxyCapabilities(Map componentCache, ComponentInstance instanceProxy, Map dataTypes) { Map> capabilities = instanceProxy.getCapabilities(); Map toscaCapabilities = new HashMap<>(); if (capabilities != null) { for (Map.Entry> entry : capabilities.entrySet()) { entry.getValue().stream().forEach(c -> convertProxyCapability(toscaCapabilities, c, dataTypes, buildCapabilityNameForComponentInstance(componentCache, instanceProxy, c))); } } else { logger.debug(NO_CAPABILITIES); } return toscaCapabilities; } /** * Allows to convert component capabilities to the tosca template substitution mappings capabilities * * @param componentsCache * @param component * @return */ public Either, ToscaError> convertSubstitutionMappingCapabilities(Map componentsCache, Component component) { Map> capabilities = component.getCapabilities(); Either, ToscaError> res; if (capabilities != null) { res = buildAddSubstitutionMappingsCapabilities(componentsCache, component, capabilities); } else { res = Either.left(Maps.newHashMap()); logger.debug(NO_CAPABILITIES); } return res; } private String buildCapNamePerOwnerByPath(Map componentsCache, CapabilityDefinition c, Component component) { return buildCapReqNamePerOwnerByPath(componentsCache, component, c.getName(), c.getPreviousName(), c.getPath()); } private void convertProxyCapability(Map toscaCapabilities, CapabilityDefinition c, Map dataTypes, String capabilityName) { createToscaCapability(toscaCapabilities, c, dataTypes, capabilityName); } private void convertCapability(Map componentsCache, Component component, Map toscaCapabilities, boolean isNodeType, CapabilityDefinition c, Map dataTypes, String capabilityName) { String name; if (StringUtils.isEmpty(c.getExternalName())) { name = isNoneBlank(capabilityName) ? capabilityName : c.getName(); if (!isNodeType && ToscaUtils.isNotComplexVfc(component)) { name = buildCapNamePerOwnerByPath(componentsCache, c, component); } } else { name = c.getExternalName(); } logger.debug("The capability {} belongs to resource {} ", name, component.getUniqueId()); createToscaCapability(toscaCapabilities, c, dataTypes, name); } private void createToscaCapability(Map toscaCapabilities, CapabilityDefinition c, Map dataTypes, String name) { ToscaCapability toscaCapability = new ToscaCapability(); toscaCapability.setDescription(c.getDescription()); toscaCapability.setType(c.getType()); List occurrences = new ArrayList<>(); occurrences.add(Integer.valueOf(c.getMinOccurrences())); if (c.getMaxOccurrences().equals(CapabilityDataDefinition.MAX_OCCURRENCES)) { occurrences.add(c.getMaxOccurrences()); } else { occurrences.add(Integer.valueOf(c.getMaxOccurrences())); } toscaCapability.setOccurrences(occurrences); toscaCapability.setValid_source_types(c.getValidSourceTypes()); List properties = c.getProperties(); if (isNotEmpty(properties)) { Map toscaProperties = new HashMap<>(); for (PropertyDefinition property : properties) { ToscaProperty toscaProperty = propertyConvertor.convertProperty(dataTypes, property, PropertyConvertor.PropertyType.CAPABILITY); toscaProperties.put(property.getName(), toscaProperty); } toscaCapability.setProperties(toscaProperties); } toscaCapabilities.put(name, toscaCapability); } private String buildCapReqNamePerOwnerByPath(Map componentsCache, Component component, String name, String previousName, List path) { if (CollectionUtils.isEmpty(path)) { return name; } String ownerId = path.get(path.size() - 1); String prefix; if (CollectionUtils.isNotEmpty(component.getGroups())) { Optional groupOpt = component.getGroups().stream().filter(g -> g.getUniqueId().equals(ownerId)).findFirst(); if (groupOpt.isPresent()) { prefix = buildCapReqNamePrefix(groupOpt.get().getNormalizedName()); if (ComponentUtilities.isNotUpdatedCapReqName(prefix, name, previousName)) { return prefix + name; } return name; } } Optional ci = component.safeGetComponentInstances().stream().filter(c -> c.getUniqueId().equals(Iterables.getLast(path))) .findFirst(); if (!ci.isPresent()) { logger.debug(FAILED_TO_FIND_CI_IN_PATH, path, component.getUniqueId()); Collections.reverse(path); logger.debug("try to reverse path {} component {}", path, component.getUniqueId()); ci = component.safeGetComponentInstances().stream().filter(c -> c.getUniqueId().equals(Iterables.getLast(path))).findFirst(); } if (ci.isPresent()) { prefix = buildCapReqNamePrefix(ci.get().getNormalizedName()); if (ComponentUtilities.isNotUpdatedCapReqName(prefix, name, previousName)) { Either buildSubstitutedName = buildSubstitutedName(componentsCache, name, previousName, path, ownerId, ci.get()); if (buildSubstitutedName.isRight()) { logger.debug("Failed buildSubstitutedName name {} path {} component {}", name, path, component.getUniqueId()); } return prefix + buildSubstitutedName.left().value(); } return name; } return StringUtils.EMPTY; } /** * Allows to build substituted name of capability\requirement of the origin component instance according to the path * * @param componentsCache * @param originComponent * @param path * @param name * @param previousName * @return */ public Either buildSubstitutedName(Map componentsCache, Component originComponent, List path, String name, String previousName) { return buildSubstitutedName(componentsCache, originComponent, path, name, previousName, null); } public Either buildSubstitutedName(Map componentsCache, Component originComponent, List path, String name, String previousName, String externalName) { if (StringUtils.isNotEmpty(externalName)) { return Either.left(externalName); } if (StringUtils.isNotEmpty(previousName)) { return Either.left(name); } StringBuilder substitutedName = new StringBuilder(); boolean nameBuiltSuccessfully = true; if (isNotEmpty(path) && ToscaUtils.isNotComplexVfc(originComponent)) { List reducedPath = getReducedPath(path); Collections.reverse(reducedPath); nameBuiltSuccessfully = appendNameRecursively(componentsCache, originComponent, reducedPath.iterator(), substitutedName); } return nameBuiltSuccessfully ? Either.left(substitutedName.append(name).toString()) : Either.right(nameBuiltSuccessfully); } protected List getReducedPathByOwner(List path, String ownerId) { logger.debug("ownerId {}, path {} ", ownerId, path); if (CollectionUtils.isEmpty(path)) { logger.debug("cannot perform reduce by owner, path to component is empty"); return path; } if (isBlank(ownerId)) { logger.debug("cannot perform reduce by owner, component owner is empty"); return path; } //reduce by owner Map map = path.stream() .collect(Collectors.toMap(it -> dropLast(it, PATH_DELIMITER), Function.identity(), (a, b) -> a.endsWith(ownerId) ? a : b)); //reduce list&duplicates and preserve order return path.stream().distinct().filter(it -> map.values().contains(it)).collect(Collectors.toList()); } private List getReducedPath(List path) { return path.stream().distinct().collect(Collectors.toList()); } private boolean appendNameRecursively(Map componentsCache, Component originComponent, Iterator instanceIdIter, StringBuilder substitutedName) { if (isNotEmpty(originComponent.getComponentInstances()) && instanceIdIter.hasNext() && ToscaUtils.isNotComplexVfc(originComponent)) { String ownerId = instanceIdIter.next(); Optional instanceOpt = originComponent.getComponentInstances().stream().filter(i -> i.getUniqueId().equals(ownerId)) .findFirst(); if (instanceOpt.isPresent()) { substitutedName.append(instanceOpt.get().getNormalizedName()).append(PATH_DELIMITER); Either getOriginRes = getOriginComponent(componentsCache, instanceOpt.get()); if (getOriginRes.isRight()) { return false; } appendNameRecursively(componentsCache, getOriginRes.left().value(), instanceIdIter, substitutedName); } else if (CollectionUtils.isNotEmpty(originComponent.getGroups())) { Optional groupOpt = originComponent.getGroups().stream().filter(g -> g.getUniqueId().equals(ownerId)).findFirst(); if (!groupOpt.isPresent()) { logger.debug("Failed to find an capability owner with uniqueId {} on a component with uniqueId {}", ownerId, originComponent.getUniqueId()); return false; } substitutedName.append(groupOpt.get().getNormalizedName()).append(PATH_DELIMITER); } else { logger.debug("Failed to find an capability owner with uniqueId {} on a component with uniqueId {}", ownerId, originComponent.getUniqueId()); return false; } } return true; } Either getOriginComponent(Map componentsCache, ComponentInstance instance) { Either result; Either getOriginRes; if (componentsCache.containsKey(instance.getActualComponentUid())) { result = Either.left(componentsCache.get(instance.getActualComponentUid())); } else { ComponentParametersView filter = getFilter(instance); getOriginRes = toscaOperationFacade.getToscaElement(instance.getActualComponentUid(), filter); if (getOriginRes.isRight()) { logger.debug("Failed to get an origin component with uniqueId {}", instance.getActualComponentUid()); result = Either.right(false); } else { final Component component = getOriginRes.left().value(); result = Either.left(component); componentsCache.put(component.getUniqueId(), component); } } return result; } private ComponentParametersView getFilter(ComponentInstance instance) { ComponentParametersView filter = new ComponentParametersView(true); filter.setIgnoreComponentInstances(false); if (instance.getIsProxy()) { filter.setIgnoreCapabilities(false); filter.setIgnoreRequirements(false); filter.setIgnoreCategories(false); } if (instance.getOriginType() == OriginTypeEnum.VF) { filter.setIgnoreGroups(false); } return filter; } }