/*- * ============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.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.addInterfaceDefinitionElement; import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.addInterfaceTypeElement; import fj.data.Either; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.ImmutableTriple; import org.apache.commons.lang3.tuple.Triple; import org.openecomp.sdc.be.components.impl.exceptions.SdcResourceNotFoundException; import org.openecomp.sdc.be.config.ConfigurationManager; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; import org.openecomp.sdc.be.model.ArtifactDefinition; 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.ComponentInstanceInput; 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.GroupInstance; import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.RelationshipInfo; import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; import org.openecomp.sdc.be.model.RequirementDefinition; import org.openecomp.sdc.be.model.Resource; import org.openecomp.sdc.be.model.Service; import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; import org.openecomp.sdc.be.model.category.CategoryDefinition; import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.jsontitan.utils.ModelConverter; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.tosca.model.SubstitutionMapping; import org.openecomp.sdc.be.tosca.model.ToscaCapability; import org.openecomp.sdc.be.tosca.model.ToscaGroupTemplate; import org.openecomp.sdc.be.tosca.model.ToscaMetadata; import org.openecomp.sdc.be.tosca.model.ToscaNodeTemplate; import org.openecomp.sdc.be.tosca.model.ToscaNodeType; import org.openecomp.sdc.be.tosca.model.ToscaPolicyTemplate; import org.openecomp.sdc.be.tosca.model.ToscaProperty; import org.openecomp.sdc.be.tosca.model.ToscaTemplate; import org.openecomp.sdc.be.tosca.model.ToscaTemplateRequirement; import org.openecomp.sdc.be.tosca.model.ToscaTopolgyTemplate; import org.openecomp.sdc.be.tosca.utils.ForwardingPathToscaUtil; import org.openecomp.sdc.be.tosca.utils.InputConverter; import org.openecomp.sdc.common.log.wrappers.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.DumperOptions.FlowStyle; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.introspector.BeanAccess; import org.yaml.snakeyaml.introspector.Property; import org.yaml.snakeyaml.introspector.PropertyUtils; import org.yaml.snakeyaml.nodes.MappingNode; import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.NodeTuple; import org.yaml.snakeyaml.nodes.Tag; import org.yaml.snakeyaml.representer.Represent; import org.yaml.snakeyaml.representer.Representer; import java.beans.IntrospectionException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; import static org.apache.commons.collections.CollectionUtils.isEmpty; import static org.apache.commons.collections.CollectionUtils.isNotEmpty; import static org.apache.commons.collections.MapUtils.isNotEmpty; import static org.apache.commons.lang.StringUtils.isNotEmpty; @org.springframework.stereotype.Component("tosca-export-handler") public class ToscaExportHandler { private ApplicationDataTypeCache dataTypeCache; private ToscaOperationFacade toscaOperationFacade; private CapabilityRequirementConverter capabilityRequirementConverter; private PolicyExportParser policyExportParser; private GroupExportParser groupExportParser; private PropertyConvertor propertyConvertor; private InputConverter inputConverter; @Autowired public ToscaExportHandler(ApplicationDataTypeCache dataTypeCache, ToscaOperationFacade toscaOperationFacade, CapabilityRequirementConverter capabilityRequirementConverter, PolicyExportParser policyExportParser, GroupExportParser groupExportParser, InputConverter inputConverter) { this.dataTypeCache = dataTypeCache; this.toscaOperationFacade = toscaOperationFacade; this.capabilityRequirementConverter = capabilityRequirementConverter; this.policyExportParser = policyExportParser; this.groupExportParser = groupExportParser; this.propertyConvertor = PropertyConvertor.getInstance(); this.inputConverter = inputConverter; } private static final Logger log = Logger.getLogger(ToscaExportHandler.class); public static final String TOSCA_VERSION = "tosca_simple_yaml_1_1"; private static final String SERVICE_NODE_TYPE_PREFIX = "org.openecomp.service."; private static final String IMPORTS_FILE_KEY = "file"; private static final String TOSCA_INTERFACE_NAME = "-interface.yml"; public static final String ASSET_TOSCA_TEMPLATE = "assettoscatemplate"; private static final String FAILED_TO_GET_DEFAULT_IMPORTS_CONFIGURATION = "convertToToscaTemplate - failed to get Default Imports section from configuration"; private static final String NOT_SUPPORTED_COMPONENT_TYPE = "Not supported component type {}"; private static final List>> DEFAULT_IMPORTS = ConfigurationManager .getConfigurationManager().getConfiguration().getDefaultImports(); public Either exportComponent(Component component) { Either toscaTemplateRes = convertToToscaTemplate(component); if (toscaTemplateRes.isRight()) { return Either.right(toscaTemplateRes.right().value()); } ToscaTemplate toscaTemplate = toscaTemplateRes.left().value(); ToscaRepresentation toscaRepresentation = this.createToscaRepresentation(toscaTemplate); return Either.left(toscaRepresentation); } public Either exportComponentInterface(Component component) { if (null == DEFAULT_IMPORTS) { log.debug(FAILED_TO_GET_DEFAULT_IMPORTS_CONFIGURATION); return Either.right(ToscaError.GENERAL_ERROR); } ToscaTemplate toscaTemplate = new ToscaTemplate(TOSCA_VERSION); toscaTemplate.setImports(new ArrayList<>(DEFAULT_IMPORTS)); Map nodeTypes = new HashMap<>(); Either toscaTemplateRes = convertInterfaceNodeType(new HashMap<>(), component, toscaTemplate, nodeTypes); if (toscaTemplateRes.isRight()) { return Either.right(toscaTemplateRes.right().value()); } toscaTemplate = toscaTemplateRes.left().value(); ToscaRepresentation toscaRepresentation = this.createToscaRepresentation(toscaTemplate); return Either.left(toscaRepresentation); } public ToscaRepresentation createToscaRepresentation(ToscaTemplate toscaTemplate) { CustomRepresenter representer = new CustomRepresenter(); DumperOptions options = new DumperOptions(); options.setAllowReadOnlyProperties(false); options.setPrettyFlow(true); options.setDefaultFlowStyle(FlowStyle.FLOW); options.setCanonical(false); representer.addClassTag(toscaTemplate.getClass(), Tag.MAP); representer.setPropertyUtils(new UnsortedPropertyUtils()); Yaml yaml = new Yaml(representer, options); String yamlAsString = yaml.dumpAsMap(toscaTemplate); StringBuilder sb = new StringBuilder(); sb.append(ConfigurationManager.getConfigurationManager().getConfiguration().getHeatEnvArtifactHeader()); sb.append(yamlAsString); sb.append(ConfigurationManager.getConfigurationManager().getConfiguration().getHeatEnvArtifactFooter()); ToscaRepresentation toscaRepresentation = new ToscaRepresentation(); toscaRepresentation.setMainYaml(sb.toString()); toscaRepresentation.setDependencies(toscaTemplate.getDependencies()); return toscaRepresentation; } public Either getDependencies(Component component) { ToscaTemplate toscaTemplate = new ToscaTemplate(null); Either>, ToscaError> fillImports = fillImports(component, toscaTemplate); if (fillImports.isRight()) { return Either.right(fillImports.right().value()); } return Either.left(fillImports.left().value().left); } private Either convertToToscaTemplate(Component component) { if (null == DEFAULT_IMPORTS) { log.debug(FAILED_TO_GET_DEFAULT_IMPORTS_CONFIGURATION); return Either.right(ToscaError.GENERAL_ERROR); } log.trace("start tosca export for {}", component.getUniqueId()); ToscaTemplate toscaTemplate = new ToscaTemplate(TOSCA_VERSION); toscaTemplate.setMetadata(convertMetadata(component)); toscaTemplate.setImports(new ArrayList<>(DEFAULT_IMPORTS)); Map nodeTypes = new HashMap<>(); if (ModelConverter.isAtomicComponent(component)) { log.trace("convert component as node type"); return convertNodeType(new HashMap<>(), component, toscaTemplate, nodeTypes); } else { log.trace("convert component as topology template"); return convertToscaTemplate(component, toscaTemplate); } } private Either convertToscaTemplate(Component component, ToscaTemplate toscaNode) { Either>, ToscaError> importsRes = fillImports(component, toscaNode); if (importsRes.isRight()) { return Either.right(importsRes.right().value()); } toscaNode = importsRes.left().value().left; Map componentCache = importsRes.left().value().right; Either, ToscaError> nodeTypesMapEither = createProxyNodeTypes(componentCache , component ); if (nodeTypesMapEither.isRight()) { log.debug("Failed to fetch normative service proxy resource by tosca name, error {}", nodeTypesMapEither.right().value()); return Either.right(nodeTypesMapEither.right().value()); } Map nodeTypesMap = nodeTypesMapEither.left().value(); if (nodeTypesMap != null && !nodeTypesMap.isEmpty()) { toscaNode.setNode_types(nodeTypesMap); } Either, TitanOperationStatus> dataTypesEither = dataTypeCache.getAll(); if (dataTypesEither.isRight()) { log.debug("Failed to retrieve all data types {}", dataTypesEither.right().value()); return Either.right(ToscaError.GENERAL_ERROR); } Map dataTypes = dataTypesEither.left().value(); ToscaTopolgyTemplate topologyTemplate = new ToscaTopolgyTemplate(); List inputDef = component.getInputs(); Map inputs = inputConverter.convertInputs(inputDef, dataTypes); if (!inputs.isEmpty()) { topologyTemplate.setInputs(inputs); } List componentInstances = component.getComponentInstances(); Map> componentInstancesProperties = component .getComponentInstancesProperties(); if (componentInstances != null && !componentInstances.isEmpty()) { Either, ToscaError> nodeTemplates = convertNodeTemplates(component, componentInstances, componentInstancesProperties, componentCache, dataTypes, topologyTemplate); if (nodeTemplates.isRight()) { return Either.right(nodeTemplates.right().value()); } log.debug("node templates converted"); topologyTemplate.setNode_templates(nodeTemplates.left().value()); } addGroupsToTopologyTemplate(component, topologyTemplate); try { addPoliciesToTopologyTemplate(component, topologyTemplate); } catch (SdcResourceNotFoundException e) { log.debug("Fail to add policies to topology template:",e); Either.right(ToscaError.GENERAL_ERROR); } SubstitutionMapping substitutionMapping = new SubstitutionMapping(); String toscaResourceName; switch (component.getComponentType()) { case RESOURCE: toscaResourceName = ((ResourceMetadataDataDefinition) component.getComponentMetadataDefinition() .getMetadataDataDefinition()).getToscaResourceName(); break; case SERVICE: toscaResourceName = SERVICE_NODE_TYPE_PREFIX + component.getComponentMetadataDefinition().getMetadataDataDefinition().getSystemName(); break; default: log.debug(NOT_SUPPORTED_COMPONENT_TYPE, component.getComponentType()); return Either.right(ToscaError.NOT_SUPPORTED_TOSCA_TYPE); } substitutionMapping.setNode_type(toscaResourceName); Either capabilities = convertCapabilities(component, substitutionMapping, componentCache); if (capabilities.isRight()) { return Either.right(capabilities.right().value()); } substitutionMapping = capabilities.left().value(); Either requirements = capabilityRequirementConverter .convertSubstitutionMappingRequirements(componentCache, component, substitutionMapping); if (requirements.isRight()) { return Either.right(requirements.right().value()); } substitutionMapping = requirements.left().value(); topologyTemplate.setSubstitution_mappings(substitutionMapping); toscaNode.setTopology_template(topologyTemplate); return Either.left(toscaNode); } private void addGroupsToTopologyTemplate(Component component, ToscaTopolgyTemplate topologyTemplate) { Map groups = groupExportParser.getGroups(component); if(groups!= null) { topologyTemplate.addGroups(groups); } } private void addPoliciesToTopologyTemplate(Component component, ToscaTopolgyTemplate topologyTemplate) throws SdcResourceNotFoundException { Map policies = policyExportParser.getPolicies(component); if(policies!= null) { topologyTemplate.addPolicies(policies); } } private ToscaMetadata convertMetadata(Component component) { return convertMetadata(component, false, null); } private ToscaMetadata convertMetadata(Component component, boolean isInstance, ComponentInstance componentInstance) { ToscaMetadata toscaMetadata = new ToscaMetadata(); toscaMetadata.setInvariantUUID(component.getInvariantUUID()); toscaMetadata.setUUID(component.getUUID()); toscaMetadata.setDescription(component.getDescription()); toscaMetadata.setName(component.getComponentMetadataDefinition().getMetadataDataDefinition().getName()); List categories = component.getCategories(); CategoryDefinition categoryDefinition = categories.get(0); toscaMetadata.setCategory(categoryDefinition.getName()); if (isInstance) { toscaMetadata.setVersion(component.getVersion()); toscaMetadata.setCustomizationUUID(componentInstance.getCustomizationUUID()); if (componentInstance.getSourceModelInvariant() != null && !componentInstance.getSourceModelInvariant().isEmpty()) { toscaMetadata.setVersion(componentInstance.getComponentVersion()); toscaMetadata.setSourceModelInvariant(componentInstance.getSourceModelInvariant()); toscaMetadata.setSourceModelUuid(componentInstance.getSourceModelUuid()); toscaMetadata.setSourceModelName(componentInstance.getSourceModelName()); toscaMetadata.setName( componentInstance.getSourceModelName() + " " + OriginTypeEnum.ServiceProxy.getDisplayValue()); toscaMetadata.setDescription(componentInstance.getDescription()); } } switch (component.getComponentType()) { case RESOURCE: Resource resource = (Resource) component; if (isInstance && componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy) { toscaMetadata.setType(componentInstance.getOriginType().getDisplayValue()); } else { toscaMetadata.setType(resource.getResourceType().name()); } toscaMetadata.setSubcategory(categoryDefinition.getSubcategories().get(0).getName()); toscaMetadata.setResourceVendor(resource.getVendorName()); toscaMetadata.setResourceVendorRelease(resource.getVendorRelease()); toscaMetadata.setResourceVendorModelNumber(resource.getResourceVendorModelNumber()); break; case SERVICE: Service service = (Service) component; toscaMetadata.setType(component.getComponentType().getValue()); toscaMetadata.setServiceType(service.getServiceType()); toscaMetadata.setServiceRole(service.getServiceRole()); toscaMetadata.setEnvironmentContext(service.getEnvironmentContext()); resolveInstantiationTypeAndSetItToToscaMetaData(toscaMetadata, service); if (!isInstance) { // DE268546 toscaMetadata.setServiceEcompNaming(((Service) component).isEcompGeneratedNaming()); toscaMetadata.setEcompGeneratedNaming(((Service) component).isEcompGeneratedNaming()); toscaMetadata.setNamingPolicy(((Service) component).getNamingPolicy()); } break; default: log.debug(NOT_SUPPORTED_COMPONENT_TYPE, component.getComponentType()); } return toscaMetadata; } private void resolveInstantiationTypeAndSetItToToscaMetaData(ToscaMetadata toscaMetadata, Service service) { if (service.getInstantiationType() != null) { toscaMetadata.setInstantiationType(service.getInstantiationType()); } else { toscaMetadata.setInstantiationType(StringUtils.EMPTY); } } private Either>, ToscaError> fillImports(Component component, ToscaTemplate toscaTemplate) { if (null == DEFAULT_IMPORTS) { log.debug(FAILED_TO_GET_DEFAULT_IMPORTS_CONFIGURATION); return Either.right(ToscaError.GENERAL_ERROR); } Map componentCache = new HashMap<>(); if (!ModelConverter.isAtomicComponent(component)) { List componentInstances = component.getComponentInstances(); if (componentInstances != null && !componentInstances.isEmpty()) { List>> additionalImports = toscaTemplate.getImports() == null ? new ArrayList<>(DEFAULT_IMPORTS) : new ArrayList<>(toscaTemplate.getImports()); List> dependecies = new ArrayList<>(); Map toscaArtifacts = component.getToscaArtifacts(); ArtifactDefinition artifactDefinition = toscaArtifacts.get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE); Map> importsListMember = new HashMap<>(); Map interfaceFiles = new HashMap<>(); interfaceFiles.put(IMPORTS_FILE_KEY, getInterfaceFilename(artifactDefinition.getArtifactName())); StringBuilder keyNameBuilder = new StringBuilder(); keyNameBuilder.append(component.getComponentType().toString().toLowerCase()); keyNameBuilder.append("-"); keyNameBuilder.append(component.getName()); keyNameBuilder.append("-interface"); importsListMember.put(keyNameBuilder.toString(), interfaceFiles); additionalImports.add(importsListMember); componentInstances.forEach(ci -> createDependency(componentCache, additionalImports, dependecies, ci)); toscaTemplate.setDependencies(dependecies); toscaTemplate.setImports(additionalImports); } } else { log.debug("currently imports supported for VF and service only"); } return Either.left(new ImmutablePair<>(toscaTemplate, componentCache)); } private void createDependency(Map componentCache, List>> imports, List> dependecies, ComponentInstance ci) { Map files = new HashMap<>(); Map> importsListMember = new HashMap<>(); StringBuilder keyNameBuilder; Component componentRI = componentCache.get(ci.getComponentUid()); if (componentRI == null) { // all resource must be only once! Either resource = toscaOperationFacade .getToscaFullElement(ci.getComponentUid()); if ((resource.isRight()) && (log.isDebugEnabled())) { log.debug("Failed to fetch resource with id {} for instance {}",ci.getComponentUid() ,ci.getUniqueId()); return ; } Component fetchedComponent = resource.left().value(); componentCache.put(fetchedComponent.getUniqueId(), fetchedComponent); if (ci.getOriginType() == OriginTypeEnum.ServiceProxy){ Either sourceService = toscaOperationFacade .getToscaFullElement(ci.getSourceModelUid()); if (sourceService.isRight() && (log.isDebugEnabled())) { log.debug("Failed to fetch source service with id {} for proxy {}", ci.getSourceModelUid(), ci.getUniqueId()); } Component fetchedSource = sourceService.left().value(); componentCache.put(fetchedSource.getUniqueId(), fetchedSource); } componentRI = fetchedComponent; Map toscaArtifacts = componentRI.getToscaArtifacts(); ArtifactDefinition artifactDefinition = toscaArtifacts.get(ASSET_TOSCA_TEMPLATE); if (artifactDefinition != null) { String artifactName = artifactDefinition.getArtifactName(); files.put(IMPORTS_FILE_KEY, artifactName); keyNameBuilder = new StringBuilder(); keyNameBuilder.append(fetchedComponent.getComponentType().toString().toLowerCase()); keyNameBuilder.append("-"); keyNameBuilder.append(ci.getComponentName()); importsListMember.put(keyNameBuilder.toString(), files); imports.add(importsListMember); dependecies.add(new ImmutableTriple<>(artifactName, artifactDefinition.getEsId(), fetchedComponent)); if (!ModelConverter.isAtomicComponent(componentRI)) { importsListMember = new HashMap<>(); Map interfaceFiles = new HashMap<>(); interfaceFiles.put(IMPORTS_FILE_KEY, getInterfaceFilename(artifactName)); keyNameBuilder.append("-interface"); importsListMember.put(keyNameBuilder.toString(), interfaceFiles); imports.add(importsListMember); } } } } public static String getInterfaceFilename(String artifactName) { return artifactName.substring(0, artifactName.lastIndexOf('.')) + ToscaExportHandler.TOSCA_INTERFACE_NAME; } private Either convertNodeType(Map componentsCache, Component component, ToscaTemplate toscaNode, Map nodeTypes) { log.debug("start convert node type for {}", component.getUniqueId()); ToscaNodeType toscaNodeType = createNodeType(component); Either, TitanOperationStatus> dataTypesEither = dataTypeCache.getAll(); if (dataTypesEither.isRight()) { log.debug("Failed to fetch all data types :", dataTypesEither.right().value()); return Either.right(ToscaError.GENERAL_ERROR); } Map dataTypes = dataTypesEither.left().value(); Either properties = propertyConvertor.convertProperties(component, toscaNodeType, dataTypes); if (properties.isRight()) { return Either.right(properties.right().value()); } toscaNodeType = properties.left().value(); log.debug("Properties converted for {}", component.getUniqueId()); // Extracted to method for code reuse return convertReqCapAndTypeName(componentsCache, component, toscaNode, nodeTypes, toscaNodeType, dataTypes); } private Either convertInterfaceNodeType(Map componentsCache, Component component, ToscaTemplate toscaNode, Map nodeTypes) { log.debug("start convert node type for {}", component.getUniqueId()); ToscaNodeType toscaNodeType = createNodeType(component); Either, TitanOperationStatus> dataTypesEither = dataTypeCache.getAll(); if (dataTypesEither.isRight()) { log.debug("Failed to fetch all data types :", dataTypesEither.right().value()); return Either.right(ToscaError.GENERAL_ERROR); } Map dataTypes = dataTypesEither.left().value(); List inputDef = component.getInputs(); Map inputs = new HashMap<>(); if (inputDef != null) { inputDef.forEach(i -> { ToscaProperty property = propertyConvertor.convertProperty(dataTypes, i, false); inputs.put(i.getName(), property); }); if (!inputs.isEmpty()) { toscaNodeType.setProperties(inputs); addInterfaceDefinitionElement(component, toscaNodeType); } } return convertReqCapAndTypeName(componentsCache, component, toscaNode, nodeTypes, toscaNodeType, dataTypes); } private Either convertReqCapAndTypeName(Map componentsCache, Component component, ToscaTemplate toscaNode, Map nodeTypes, ToscaNodeType toscaNodeType, Map dataTypes) { Either capabilities = convertCapabilities(componentsCache, component, toscaNodeType, dataTypes); if (capabilities.isRight()) { return Either.right(capabilities.right().value()); } toscaNodeType = capabilities.left().value(); log.debug("Capabilities converted for {}", component.getUniqueId()); Either requirements = capabilityRequirementConverter.convertRequirements(componentsCache, component, toscaNodeType); if (requirements.isRight()) { return Either.right(requirements.right().value()); } toscaNodeType = requirements.left().value(); log.debug("Requirements converted for {}", component.getUniqueId()); String toscaResourceName; switch (component.getComponentType()) { case RESOURCE: toscaResourceName = ((ResourceMetadataDataDefinition) component.getComponentMetadataDefinition() .getMetadataDataDefinition()).getToscaResourceName(); break; case SERVICE: toscaResourceName = SERVICE_NODE_TYPE_PREFIX + component.getComponentMetadataDefinition().getMetadataDataDefinition().getSystemName(); break; default: log.debug(NOT_SUPPORTED_COMPONENT_TYPE, component.getComponentType()); return Either.right(ToscaError.NOT_SUPPORTED_TOSCA_TYPE); } nodeTypes.put(toscaResourceName, toscaNodeType); toscaNode.setNode_types(nodeTypes); log.debug("finish convert node type for {}", component.getUniqueId()); return Either.left(toscaNode); } private Either, ToscaError> convertNodeTemplates(Component component, List componentInstances, Map> componentInstancesProperties, Map componentCache, Map dataTypes, ToscaTopolgyTemplate topologyTemplate) { Either, ToscaError> convertNodeTemplatesRes = null; log.debug("start convert topology template for {} for type {}", component.getUniqueId(), component.getComponentType()); Map nodeTemplates = new HashMap<>(); Map> componentInstancesInputs = component.getComponentInstancesInputs(); Map groupsMap = null; for (ComponentInstance componentInstance : componentInstances) { ToscaNodeTemplate nodeTemplate = new ToscaNodeTemplate(); nodeTemplate.setType(componentInstance.getToscaComponentName()); Either originComponentRes = capabilityRequirementConverter .getOriginComponent(componentCache, componentInstance); if (originComponentRes.isRight()) { convertNodeTemplatesRes = Either.right(ToscaError.NODE_TYPE_REQUIREMENT_ERROR); break; } Either requirements = convertComponentInstanceRequirements(component, componentInstance, component.getComponentInstancesRelations(), nodeTemplate, originComponentRes.left().value(), componentCache); if (requirements.isRight()) { convertNodeTemplatesRes = Either.right(requirements.right().value()); break; } String instanceUniqueId = componentInstance.getUniqueId(); log.debug("Component instance Requirements converted for instance {}", instanceUniqueId); nodeTemplate = requirements.left().value(); Component originalComponent = componentCache.get(componentInstance.getActualComponentUid()); if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy){ Component componentOfProxy = componentCache.get(componentInstance.getComponentUid()); nodeTemplate.setMetadata(convertMetadata(componentOfProxy, true, componentInstance)); } else { nodeTemplate.setMetadata(convertMetadata(originalComponent, true, componentInstance)); } Either capabilities = capabilityRequirementConverter .convertComponentInstanceCapabilities(componentInstance, dataTypes, nodeTemplate); if (capabilities.isRight()) { convertNodeTemplatesRes = Either.right(capabilities.right().value()); break; } log.debug("Component instance Capabilities converted for instance {}", instanceUniqueId); nodeTemplate = capabilities.left().value(); Map props = new HashMap<>(); if (originalComponent.getComponentType() == ComponentTypeEnum.RESOURCE) { // Adds the properties of parent component to map addPropertiesOfParentComponent(dataTypes, originalComponent, props); } if (null != componentInstancesProperties && componentInstancesProperties.containsKey(instanceUniqueId)) { addPropertiesOfComponentInstance(componentInstancesProperties, dataTypes, instanceUniqueId, props); } if (componentInstancesInputs != null && componentInstancesInputs.containsKey(instanceUniqueId)) { addComponentInstanceInputs(dataTypes, componentInstancesInputs, instanceUniqueId, props); } if (!props.isEmpty()) { nodeTemplate.setProperties(props); } List groupInstances = componentInstance.getGroupInstances(); if (groupInstances != null) { if (groupsMap == null) { groupsMap = new HashMap<>(); } for (GroupInstance groupInst : groupInstances) { boolean addToTosca = true; List artifacts = groupInst.getArtifacts(); if (artifacts == null || artifacts.isEmpty()) { addToTosca = false; } if (addToTosca) { ToscaGroupTemplate toscaGroup = groupExportParser.getToscaGroupTemplate(groupInst, componentInstance.getInvariantName()); groupsMap.put(groupInst.getName(), toscaGroup); } } } nodeTemplates.put(componentInstance.getName(), nodeTemplate); } if (groupsMap != null) { log.debug("instance groups added"); topologyTemplate.addGroups(groupsMap); } if (component.getComponentType() == ComponentTypeEnum.SERVICE && isNotEmpty(((Service) component).getForwardingPaths())) { log.debug("Starting converting paths for component {}, name {}", component.getUniqueId(), component.getName()); ForwardingPathToscaUtil.addForwardingPaths((Service) component, nodeTemplates, capabilityRequirementConverter, componentCache, toscaOperationFacade); log.debug("Finished converting paths for component {}, name {}", component.getUniqueId(), component.getName()); } if (convertNodeTemplatesRes == null) { convertNodeTemplatesRes = Either.left(nodeTemplates); } log.debug("finish convert topology template for {} for type {}", component.getUniqueId(), component.getComponentType()); return convertNodeTemplatesRes; } private void addComponentInstanceInputs(Map dataTypes, Map> componentInstancesInputs, String instanceUniqueId, Map props) { List instanceInputsList = componentInstancesInputs.get(instanceUniqueId); if (instanceInputsList != null) { instanceInputsList.forEach(input -> { Supplier supplier = () -> input.getValue() != null && !input.getValue().isEmpty() ? input.getValue() : input.getDefaultValue(); propertyConvertor.convertAndAddValue(dataTypes, props, input, supplier); }); } } private void addPropertiesOfComponentInstance( Map> componentInstancesProperties, Map dataTypes, String instanceUniqueId, Map props) { if (isNotEmpty(componentInstancesProperties)) { componentInstancesProperties.get(instanceUniqueId) // Converts and adds each value to property map .forEach(prop -> propertyConvertor.convertAndAddValue(dataTypes, props, prop, prop::getValue)); } } private void addPropertiesOfParentComponent(Map dataTypes, Component componentOfInstance, Map props) { List componentProperties = ((Resource) componentOfInstance).getProperties(); if (isNotEmpty(componentProperties)) { componentProperties.stream() // Filters out properties with empty default values .filter(prop -> isNotEmpty(prop.getDefaultValue())) // Converts and adds each value to property map .forEach(prop -> propertyConvertor.convertAndAddValue(dataTypes, props, prop, prop::getDefaultValue)); } } private ToscaNodeType createNodeType(Component component) { ToscaNodeType toscaNodeType = new ToscaNodeType(); if (ModelConverter.isAtomicComponent(component)) { if (((Resource) component).getDerivedFrom() != null) { toscaNodeType.setDerived_from(((Resource) component).getDerivedFrom().get(0)); } toscaNodeType.setDescription(component.getDescription()); } else { String derivedFrom = null != component.getDerivedFromGenericType() ? component.getDerivedFromGenericType() : "tosca.nodes.Root"; toscaNodeType.setDerived_from(derivedFrom); } return toscaNodeType; } private Either, ToscaError> createProxyNodeTypes(Map componentCache ,Component container ) { Map nodeTypesMap = new HashMap<>(); Either, ToscaError> res = Either.left(nodeTypesMap); List componentInstances = container.getComponentInstances(); if (componentInstances == null || componentInstances.isEmpty()) { return res; } Map serviceProxyInstanceList = new HashMap<>(); List proxyInst = componentInstances.stream() .filter(p -> p.getOriginType().name().equals(OriginTypeEnum.ServiceProxy.name())) .collect(Collectors.toList()); if (proxyInst != null && !proxyInst.isEmpty()) { for (ComponentInstance inst : proxyInst) { serviceProxyInstanceList.put(inst.getToscaComponentName(), inst); } } if (serviceProxyInstanceList.isEmpty()) { return res; } ComponentParametersView filter = new ComponentParametersView(true); filter.setIgnoreCapabilities(false); filter.setIgnoreComponentInstances(false); Either serviceProxyOrigin = toscaOperationFacade .getLatestByName("serviceProxy"); if (serviceProxyOrigin.isRight()) { log.debug("Failed to fetch normative service proxy resource by tosca name, error {}", serviceProxyOrigin.right().value()); return Either.right(ToscaError.NOT_SUPPORTED_TOSCA_TYPE); } Component origComponent = serviceProxyOrigin.left().value(); for (Entry entryProxy : serviceProxyInstanceList.entrySet()) { Component serviceComponent = null; ComponentParametersView componentParametersView = new ComponentParametersView(); componentParametersView.disableAll(); componentParametersView.setIgnoreCategories(false); Either service = toscaOperationFacade .getToscaElement(entryProxy.getValue().getSourceModelUid(), componentParametersView); if (service.isRight()) { log.debug("Failed to fetch resource with id {} for instance {}", entryProxy.getValue().getSourceModelUid(), entryProxy.getValue().getName()); } else { serviceComponent = service.left().value(); } ToscaNodeType toscaNodeType = createProxyNodeType(componentCache , origComponent, serviceComponent, entryProxy.getValue()); nodeTypesMap.put(entryProxy.getKey(), toscaNodeType); } return Either.left(nodeTypesMap); } private ToscaNodeType createProxyNodeType(Map componentCache , Component origComponent, Component proxyComponent, ComponentInstance instance) { ToscaNodeType toscaNodeType = new ToscaNodeType(); String derivedFrom = ((Resource) origComponent).getToscaResourceName(); toscaNodeType.setDerived_from(derivedFrom); Either, TitanOperationStatus> dataTypesEither = dataTypeCache.getAll(); if (dataTypesEither.isRight()) { log.debug("Failed to retrieve all data types {}", dataTypesEither.right().value()); } Map dataTypes = dataTypesEither.left().value(); Map capabilities = this.capabilityRequirementConverter .convertProxyCapabilities( componentCache ,origComponent, proxyComponent, instance, dataTypes); toscaNodeType.setCapabilities(capabilities); return toscaNodeType; } private Either convertComponentInstanceRequirements(Component component, ComponentInstance componentInstance, List relations, ToscaNodeTemplate nodeTypeTemplate, Component originComponent, Map componentCache) { List> toscaRequirements = new ArrayList<>(); if (!addRequirements(component, componentInstance, relations, originComponent, toscaRequirements, componentCache)) { log.debug("Failed to convert component instance requirements for the component instance {}. ", componentInstance.getName()); return Either.right(ToscaError.NODE_TYPE_REQUIREMENT_ERROR); } if (!toscaRequirements.isEmpty()) { nodeTypeTemplate.setRequirements(toscaRequirements); } log.debug("Finished to convert requirements for the node type {} ", componentInstance.getName()); return Either.left(nodeTypeTemplate); } private boolean addRequirements(Component component, ComponentInstance componentInstance, List relations, Component originComponent, List> toscaRequirements, Map componentCache) { List filteredRelations = relations.stream() .filter(p -> componentInstance.getUniqueId().equals(p.getFromNode())).collect(Collectors.toList()); return isEmpty(filteredRelations) || filteredRelations.stream() .allMatch(rel -> addRequirement(componentInstance, originComponent, component.getComponentInstances(), rel, toscaRequirements, componentCache)); } private boolean addRequirement(ComponentInstance fromInstance, Component fromOriginComponent, List instancesList, RequirementCapabilityRelDef rel, List> toscaRequirements, Map componentCache) { boolean result = true; Map> reqMap = fromOriginComponent.getRequirements(); RelationshipInfo reqAndRelationshipPair = rel.getRelationships().get(0).getRelation(); Either getOriginRes = null; Optional reqOpt = Optional.empty(); Component toOriginComponent = null; Optional capOpt = Optional.empty(); ComponentInstance toInstance = instancesList.stream().filter(i -> rel.getToNode().equals(i.getUniqueId())) .findFirst().orElse(null); if (toInstance == null) { log.debug("Failed to find a relation from the node {} to the node {}", fromInstance.getName(), rel.getToNode()); result = false; } if (result) { reqOpt = findRequirement(fromOriginComponent, reqMap, reqAndRelationshipPair, fromInstance.getUniqueId()); if (!reqOpt.isPresent()) { log.debug("Failed to find a requirement with uniqueId {} on a component with uniqueId {}", reqAndRelationshipPair.getRequirementUid(), fromOriginComponent.getUniqueId()); result = false; } } if (result) { ComponentParametersView filter = new ComponentParametersView(true); filter.setIgnoreComponentInstances(false); filter.setIgnoreCapabilities(false); filter.setIgnoreGroups(false); getOriginRes = toscaOperationFacade.getToscaElement(toInstance.getActualComponentUid(), filter); if (getOriginRes.isRight()) { log.debug("Failed to build substituted name for the requirement {}. Failed to get an origin component with uniqueId {}", reqOpt.get().getName(), toInstance.getActualComponentUid()); result = false; } } if (result) { toOriginComponent = getOriginRes.left().value(); capOpt = toOriginComponent.getCapabilities().get(reqOpt.get().getCapability()).stream() .filter(c -> isCapabilityBelongToRelation(reqAndRelationshipPair, c)).findFirst(); if (!capOpt.isPresent()) { capOpt = findCapability(reqAndRelationshipPair, toOriginComponent, fromOriginComponent, reqOpt.get()); if(!capOpt.isPresent()){ result = false; log.debug("Failed to find a capability with name {} on a component with uniqueId {}", reqAndRelationshipPair.getCapability(), fromOriginComponent.getUniqueId()); } } } if (result) { result = buildAndAddRequirement(toscaRequirements, fromOriginComponent, toOriginComponent, capOpt.get(), reqOpt.get(), reqAndRelationshipPair, toInstance, componentCache); } return result; } private boolean isCapabilityBelongToRelation(RelationshipInfo reqAndRelationshipPair, CapabilityDefinition capability) { return capability.getName().equals(reqAndRelationshipPair.getCapability()) && (capability.getOwnerId() !=null && capability.getOwnerId().equals(reqAndRelationshipPair.getCapabilityOwnerId())); } private Optional findCapability(RelationshipInfo reqAndRelationshipPair, Component toOriginComponent, Component fromOriginComponent, RequirementDefinition requirement) { Optional cap = toOriginComponent.getCapabilities().get(requirement.getCapability()).stream().filter(c -> c.getType().equals(requirement.getCapability())).findFirst(); if (!cap.isPresent()) { log.debug("Failed to find a capability with name {} on a component with uniqueId {}", reqAndRelationshipPair.getCapability(), fromOriginComponent.getUniqueId()); } return cap; } private boolean buildAndAddRequirement(List> toscaRequirements, Component fromOriginComponent, Component toOriginComponent, CapabilityDefinition capability, RequirementDefinition requirement, RelationshipInfo reqAndRelationshipPair, ComponentInstance toInstance, Map componentCache) { List reducedPath = capability.getPath(); if(capability.getOwnerId() !=null){ reducedPath = capabilityRequirementConverter.getReducedPathByOwner(capability.getPath() , capability.getOwnerId() ); } Either buildCapNameRes = capabilityRequirementConverter.buildSubstitutedName(componentCache, toOriginComponent, reducedPath, reqAndRelationshipPair.getCapability(), capability.getPreviousName()); if (buildCapNameRes.isRight()) { log.debug( "Failed to build a substituted capability name for the capability with name {} on a component with uniqueId {}", reqAndRelationshipPair.getCapability(), fromOriginComponent.getUniqueId()); return false; } Either buildReqNameRes = capabilityRequirementConverter.buildSubstitutedName(componentCache, fromOriginComponent, requirement.getPath(), reqAndRelationshipPair.getRequirement(), requirement.getPreviousName()); if (buildReqNameRes.isRight()) { log.debug( "Failed to build a substituted requirement name for the requirement with name {} on a component with uniqueId {}", reqAndRelationshipPair.getRequirement(), fromOriginComponent.getUniqueId()); return false; } ToscaTemplateRequirement toscaRequirement = new ToscaTemplateRequirement(); Map toscaReqMap = new HashMap<>(); toscaRequirement.setNode(toInstance.getName()); toscaRequirement.setCapability(buildCapNameRes.left().value()); toscaReqMap.put(buildReqNameRes.left().value(), toscaRequirement); toscaRequirements.add(toscaReqMap); return true; } private Optional findRequirement(Component fromOriginComponent, Map> reqMap, RelationshipInfo reqAndRelationshipPair, String fromInstanceId) { for(List reqList: reqMap.values()){ Optional reqOpt = reqList.stream().filter(r -> isRequirementBelongToRelation(fromOriginComponent, reqAndRelationshipPair, r, fromInstanceId)).findFirst(); if(reqOpt.isPresent()){ return reqOpt; } } return Optional.empty(); } /** * Allows detecting the requirement belonging to the received relationship * The detection logic is: A requirement belongs to a relationship IF 1.The * name of the requirement equals to the "requirement" field of the * relation; AND 2. In case of a non-atomic resource, OwnerId of the * requirement equals to requirementOwnerId of the relation OR uniqueId of * toInstance equals to capabilityOwnerId of the relation */ private boolean isRequirementBelongToRelation(Component originComponent, RelationshipInfo reqAndRelationshipPair, RequirementDefinition requirement, String fromInstanceId) { if (!StringUtils.equals(requirement.getName(), reqAndRelationshipPair.getRequirement())) { log.debug("Failed to find a requirement with name {} and reqAndRelationshipPair {}", requirement.getName(), reqAndRelationshipPair.getRequirement()); return false; } return ModelConverter.isAtomicComponent(originComponent) || isRequirementBelongToOwner(reqAndRelationshipPair, requirement, fromInstanceId, originComponent); } private boolean isRequirementBelongToOwner(RelationshipInfo reqAndRelationshipPair, RequirementDefinition requirement, String fromInstanceId, Component originComponent) { return StringUtils.equals(requirement.getOwnerId(), reqAndRelationshipPair.getRequirementOwnerId()) || (isCvfc(originComponent) && StringUtils.equals(fromInstanceId, reqAndRelationshipPair.getRequirementOwnerId())); } private boolean isCvfc(Component component) { return component.getComponentType() == ComponentTypeEnum.RESOURCE && ((Resource) component).getResourceType() == ResourceTypeEnum.CVFC; } private Either convertCapabilities(Component component, SubstitutionMapping substitutionMappings, Map componentCache) { Either result = Either.left(substitutionMappings); Either, ToscaError> toscaCapabilitiesRes = capabilityRequirementConverter .convertSubstitutionMappingCapabilities(componentCache, component); if (toscaCapabilitiesRes.isRight()) { result = Either.right(toscaCapabilitiesRes.right().value()); log.debug("Failed convert capabilities for the component {}. ", component.getName()); } else if (isNotEmpty(toscaCapabilitiesRes.left().value())) { substitutionMappings.setCapabilities(toscaCapabilitiesRes.left().value()); log.debug("Finish convert capabilities for the component {}. ", component.getName()); } log.debug("Finished to convert capabilities for the component {}. ", component.getName()); return result; } private Either convertCapabilities(Map componentsCache, Component component, ToscaNodeType nodeType, Map dataTypes) { Map toscaCapabilities = capabilityRequirementConverter.convertCapabilities(componentsCache, component, dataTypes); if (!toscaCapabilities.isEmpty()) { nodeType.setCapabilities(toscaCapabilities); } log.debug("Finish convert Capabilities for node type"); return Either.left(nodeType); } private static class CustomRepresenter extends Representer { public CustomRepresenter() { super(); // null representer is exceptional and it is stored as an instance // variable. this.nullRepresenter = new RepresentNull(); } @Override protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) { if (propertyValue == null) { return null; } else { // skip not relevant for Tosca property if ("dependencies".equals(property.getName())) { return null; } NodeTuple defaultNode = super.representJavaBeanProperty(javaBean, property, propertyValue, customTag); return "_defaultp_".equals(property.getName()) ? new NodeTuple(representData("default"), defaultNode.getValueNode()) : defaultNode; } } @Override protected MappingNode representJavaBean(Set properties, Object javaBean) { // remove the bean type from the output yaml (!! ...) if (!classTags.containsKey(javaBean.getClass())) { addClassTag(javaBean.getClass(), Tag.MAP); } return super.representJavaBean(properties, javaBean); } private class RepresentNull implements Represent { @Override public Node representData(Object data) { // possible values are here http://yaml.org/type/null.html return representScalar(Tag.NULL, ""); } } } private static class UnsortedPropertyUtils extends PropertyUtils { @Override protected Set createPropertySet(Class type, BeanAccess bAccess) throws IntrospectionException { Collection fields = getPropertiesMap(type, BeanAccess.FIELD).values(); return new LinkedHashSet<>(fields); } } }