2  * Copyright © 2016-2017 European Support Limited
 
   4  * Licensed under the Apache License, Version 2.0 (the "License");
 
   5  * you may not use this file except in compliance with the License.
 
   6  * You may obtain a copy of the License at
 
   8  *      http://www.apache.org/licenses/LICENSE-2.0
 
  10  * Unless required by applicable law or agreed to in writing, software
 
  11  * distributed under the License is distributed on an "AS IS" BASIS,
 
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  13  * See the License for the specific language governing permissions and
 
  14  * limitations under the License.
 
  17 package org.openecomp.sdc.enrichment.impl.tosca;
 
  19 import org.apache.commons.collections4.CollectionUtils;
 
  20 import org.apache.commons.collections4.MapUtils;
 
  21 import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum;
 
  22 import org.openecomp.sdc.datatypes.error.ErrorMessage;
 
  23 import org.openecomp.sdc.enrichment.impl.tosca.model.PortMirroringConnectionPointDescription;
 
  24 import org.openecomp.sdc.tosca.datatypes.ToscaElementTypes;
 
  25 import org.openecomp.sdc.tosca.datatypes.ToscaNodeType;
 
  26 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
 
  27 import org.openecomp.sdc.tosca.datatypes.model.CapabilityAssignment;
 
  28 import org.openecomp.sdc.tosca.datatypes.model.Import;
 
  29 import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate;
 
  30 import org.openecomp.sdc.tosca.datatypes.model.NodeType;
 
  31 import org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition;
 
  32 import org.openecomp.sdc.tosca.datatypes.model.RequirementAssignment;
 
  33 import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate;
 
  34 import org.openecomp.sdc.tosca.services.DataModelUtil;
 
  35 import org.openecomp.sdc.tosca.services.ToscaAnalyzerService;
 
  36 import org.openecomp.sdc.tosca.services.ToscaConstants;
 
  37 import org.openecomp.sdc.tosca.services.ToscaUtil;
 
  38 import org.openecomp.sdc.tosca.services.impl.ToscaAnalyzerServiceImpl;
 
  39 import org.openecomp.sdc.translator.services.heattotosca.HeatToToscaUtil;
 
  40 import org.openecomp.sdc.translator.services.heattotosca.globaltypes.GlobalTypesGenerator;
 
  42 import java.util.ArrayList;
 
  43 import java.util.Arrays;
 
  44 import java.util.HashMap;
 
  45 import java.util.HashSet;
 
  46 import java.util.LinkedList;
 
  47 import java.util.List;
 
  49 import java.util.Objects;
 
  50 import java.util.Optional;
 
  52 import java.util.stream.Collectors;
 
  54 import static org.openecomp.sdc.tosca.services.DataModelUtil.getClonedObject;
 
  55 import static org.openecomp.sdc.tosca.services.ToscaConstants.PORT_MIRRORING_CAPABILITY_CP_PROPERTY_NAME;
 
  56 import static org.openecomp.sdc.tosca.services.ToscaConstants.PORT_MIRRORING_CAPABILITY_ID;
 
  58 public class PortMirroringEnricher {
 
  59   //Map of service template file name and map of all port node template ids, node template
 
  60   private Map<String, Map<String, NodeTemplate>> portNodeTemplates = new HashMap<>();
 
  61   //Map of service template file name and map of external port node template ids, node template
 
  62   private Map<String, Map<String, NodeTemplate>> externalPortNodeTemplates = new HashMap<>();
 
  63   //Map of substitution service template name and the list of ports with link requirement from
 
  65   private Map<String, List<String>> portNodeTemplateIdsFromAbstract = new HashMap<>();
 
  66   private Map<String, ServiceTemplate> globalTypesServiceTemplate =
 
  67       GlobalTypesGenerator.getGlobalTypesServiceTemplate(OnboardingTypesEnum.ZIP);
 
  70    * Enrich tosca for port mirroring.
 
  72    * @param toscaServiceModel the tosca service model
 
  73    * @return the map          Error descriptor map
 
  75   public Map<String, List<ErrorMessage>> enrich(ToscaServiceModel toscaServiceModel) {
 
  76     Map<String, List<ErrorMessage>> errors = new HashMap<>();
 
  77     Map<String, ServiceTemplate> serviceTemplates = toscaServiceModel.getServiceTemplates();
 
  78     serviceTemplates.entrySet().stream()
 
  79         //Skipping the service templates which do not contain topology template
 
  80         .filter(serviceTemplateEntry -> serviceTemplateEntry.getValue()
 
  81             .getTopology_template() != null)
 
  82         .forEach(serviceTemplateEntry ->
 
  83             //Collect all the ports across all the service templates
 
  84             collectPorts(serviceTemplateEntry.getValue()));
 
  85     //Collect External ports from the list of all ports collected above
 
  86     filterExternalPorts(toscaServiceModel);
 
  87     //Handle external port changes
 
  88     handleExternalPorts(toscaServiceModel);
 
  92   private void collectPorts(ServiceTemplate serviceTemplate) {
 
  93     Map<String, NodeTemplate> nodeTemplates =
 
  94         serviceTemplate.getTopology_template().getNode_templates();
 
  95     if (Objects.nonNull(nodeTemplates)) {
 
  96       //Get all concrete port node templates from the service template
 
  97       Map<String, NodeTemplate> serviceTemplatePortNodeTemplates = nodeTemplates.entrySet().stream()
 
  98           .filter(nodeTemplateEntry -> (Objects.nonNull(nodeTemplateEntry.getValue()))
 
  99               && (isPortNodeTemplate(nodeTemplateEntry.getValue().getType())))
 
 100           .collect(Collectors.toMap(nodeTemplateEntry -> nodeTemplateEntry.getKey(),
 
 101               nodeTemplateEntry -> nodeTemplateEntry.getValue()));
 
 103       portNodeTemplates.put(ToscaUtil.getServiceTemplateFileName(serviceTemplate),
 
 104           serviceTemplatePortNodeTemplates);
 
 106       //Get all linked internal ports from abstract node template link requirements
 
 107       List<String> abstractLinkedPortNodeTemplates = new ArrayList<>();
 
 108       for (Map.Entry<String, NodeTemplate> nodeTemplateEntry : nodeTemplates.entrySet()) {
 
 109         NodeTemplate nodeTemplate = nodeTemplateEntry.getValue();
 
 110         if (isSubstitutableNodeTemplate(nodeTemplate)) {
 
 111           List<Map<String, RequirementAssignment>> requirements = nodeTemplate.getRequirements();
 
 112           if (Objects.nonNull(requirements)) {
 
 113             for (Map<String, RequirementAssignment> requirement : requirements) {
 
 114               String requirementId = requirement.keySet().iterator().next();
 
 115               String abstractLinkRequirementIdPrefix = ToscaConstants.LINK_REQUIREMENT_ID + "_";
 
 116               if (requirementId.startsWith(abstractLinkRequirementIdPrefix)) {
 
 117                 //Collect port node template ids from the link requirement ids in the abstract
 
 119                 abstractLinkedPortNodeTemplates.add(requirementId.substring(requirementId
 
 124           if (CollectionUtils.isNotEmpty(abstractLinkedPortNodeTemplates)) {
 
 125             //Populate a map of the substitution service templates and list of internal ports
 
 126             addCollectedPortsToAbstractServiceTemplatePortMap(nodeTemplate,
 
 127                 abstractLinkedPortNodeTemplates);
 
 134   private void addCollectedPortsToAbstractServiceTemplatePortMap(NodeTemplate nodeTemplate,
 
 136                                                                      abstractLinkedPortNodeTemplates) {
 
 137     String substitutionServiceTemplateName = null;
 
 138     if (nodeTemplate.getProperties() != null) {
 
 139       Map serviceTemplateFilter = (Map<String, Object>) nodeTemplate.getProperties()
 
 140           .get(ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME);
 
 141       substitutionServiceTemplateName = (String)
 
 142           serviceTemplateFilter.get(ToscaConstants.SUBSTITUTE_SERVICE_TEMPLATE_PROPERTY_NAME);
 
 143       if (Objects.nonNull(substitutionServiceTemplateName)) {
 
 144         if (portNodeTemplateIdsFromAbstract.containsKey(substitutionServiceTemplateName)) {
 
 145           List<String> portList =
 
 146               portNodeTemplateIdsFromAbstract.get(substitutionServiceTemplateName);
 
 147           portList.addAll(abstractLinkedPortNodeTemplates);
 
 148           portNodeTemplateIdsFromAbstract.put(substitutionServiceTemplateName, portList);
 
 150           portNodeTemplateIdsFromAbstract.put(substitutionServiceTemplateName,
 
 151               abstractLinkedPortNodeTemplates);
 
 157   private void filterExternalPorts(ToscaServiceModel toscaServiceModel) {
 
 158     for (Map.Entry<String, Map<String, NodeTemplate>> portNodeTemplateEntry : portNodeTemplates
 
 160       Map<String, NodeTemplate> externalPorts = new HashMap<>();
 
 161       String serviceTemplateFileName = portNodeTemplateEntry.getKey();
 
 162       Map<String, NodeTemplate> portNodeTemplateMap = portNodeTemplateEntry.getValue();
 
 163       for (Map.Entry<String, NodeTemplate> portNodeTemplate : portNodeTemplateMap.entrySet()) {
 
 164         String nodeTemplateId = portNodeTemplate.getKey();
 
 165         NodeTemplate nodeTemplate = portNodeTemplate.getValue();
 
 166         String newPortNodeType = nodeTemplate.getType();
 
 167         if (!isInternalPort(serviceTemplateFileName, nodeTemplateId, nodeTemplate)) {
 
 169           externalPorts.putIfAbsent(nodeTemplateId, nodeTemplate);
 
 172       externalPortNodeTemplates.putIfAbsent(serviceTemplateFileName, externalPorts);
 
 176   private void updateExternalPortNodeTemplate(NodeTemplate externalPortNodeTemplate,
 
 177                                               ToscaServiceModel toscaServiceModel) {
 
 178     String currentPortNodeType = externalPortNodeTemplate.getType();
 
 179     if (currentPortNodeType.equals(ToscaNodeType.CONTRAIL_PORT)
 
 180         || currentPortNodeType.equals(ToscaNodeType.CONTRAILV2_VIRTUAL_MACHINE_INTERFACE)) {
 
 181       //Set external contrail port node type
 
 182       externalPortNodeTemplate.setType(ToscaNodeType.EXTERNAL_CONTRAIL_PORT);
 
 183       addPortMirroringCapability(externalPortNodeTemplate);
 
 184     } else if (currentPortNodeType.equals(ToscaNodeType.NEUTRON_PORT)) {
 
 185       //Set external neutron port node type
 
 186       externalPortNodeTemplate.setType(ToscaNodeType.EXTERNAL_NEUTRON_PORT);
 
 187       addPortMirroringCapability(externalPortNodeTemplate);
 
 191   private void handleExternalPorts(ToscaServiceModel toscaServiceModel) {
 
 193     for (Map.Entry<String, Map<String, NodeTemplate>> entry : externalPortNodeTemplates
 
 195       String serviceTemplateName = entry.getKey();
 
 196       ServiceTemplate serviceTemplate =
 
 197           toscaServiceModel.getServiceTemplates().get(serviceTemplateName);
 
 198       Map<String, NodeTemplate> externalNodeTemplates = entry.getValue();
 
 199       if (MapUtils.isNotEmpty(externalNodeTemplates)) {
 
 200         for (Map.Entry<String, NodeTemplate> externalNodeTemplate : externalNodeTemplates
 
 202           String externalPortNodeTemplateId = externalNodeTemplate.getKey();
 
 203           updateExternalPortNodeTemplate(externalNodeTemplate.getValue(), toscaServiceModel);
 
 204           if (serviceTemplate.getTopology_template().getSubstitution_mappings() != null) {
 
 205             //Add port mirroring capability to substitution mapping for external ports
 
 206             addPortMirroringSubstitutionMappingCapability(serviceTemplate,
 
 207                 externalPortNodeTemplateId);
 
 209           handleExternalPortProperties(externalNodeTemplate.getValue(), serviceTemplate, toscaServiceModel);
 
 211         addGlobalTypeImport(serviceTemplate);
 
 216   private void handleExternalPortProperties(NodeTemplate portNodeTemplate,
 
 217                                             ServiceTemplate serviceTemplate,
 
 218                                             ToscaServiceModel toscaServiceModel){
 
 220     ToscaAnalyzerService toscaAnalyzerService = new ToscaAnalyzerServiceImpl();
 
 221     String externalPortType = portNodeTemplate.getType();
 
 222     Map<String, PropertyDefinition> globalTypesportProperties = new HashMap<>();
 
 223     NodeType flatNodeType =
 
 224         (NodeType) toscaAnalyzerService.getFlatEntity(ToscaElementTypes.NODE_TYPE, externalPortType, serviceTemplate, toscaServiceModel);
 
 225     globalTypesportProperties.putAll(flatNodeType.getProperties());
 
 227     Map<String, Object> properties = portNodeTemplate.getProperties();
 
 228     Map<String, Object> filteredProperties = new HashMap<>();
 
 230     if(MapUtils.isEmpty(properties)){
 
 234     for(Map.Entry<String, Object> propertyEntry: properties.entrySet()){
 
 235       if(globalTypesportProperties.containsKey(propertyEntry.getKey())){
 
 236         filteredProperties.put(propertyEntry.getKey(), propertyEntry.getValue());
 
 240     if(!MapUtils.isEmpty(filteredProperties)) {
 
 241       portNodeTemplate.setProperties(filteredProperties);
 
 243       portNodeTemplate.setProperties(null);
 
 248   private void addPortMirroringSubstitutionMappingCapability(ServiceTemplate serviceTemplate,
 
 249                                                              String externalPortNodeTemplateId) {
 
 250     List<String> portMirroringCapability = new LinkedList<>();
 
 251     portMirroringCapability.add(externalPortNodeTemplateId);
 
 252     portMirroringCapability.add(PORT_MIRRORING_CAPABILITY_ID);
 
 253     String substitutionMappingCapabilityId = PORT_MIRRORING_CAPABILITY_ID + "_"
 
 254         + externalPortNodeTemplateId;
 
 255     DataModelUtil.addSubstitutionMappingCapability(serviceTemplate,
 
 256         substitutionMappingCapabilityId, portMirroringCapability);
 
 259   private void addPortMirroringCapability(NodeTemplate portNodeTemplate) {
 
 260     Map<String, Object> portMirroringCapabilityProperties = new HashMap<>();
 
 261     PortMirroringConnectionPointDescription connectionPoint = new
 
 262         PortMirroringConnectionPointDescription();
 
 263     //Get Network role property
 
 264     if (Objects.nonNull(portNodeTemplate.getProperties())) {
 
 265       Object networkRolePropertyValue =
 
 266           portNodeTemplate.getProperties().get(ToscaConstants.PORT_NETWORK_ROLE_PROPERTY_NAME);
 
 267       if (Objects.nonNull(networkRolePropertyValue)) {
 
 268         Object portMirroringNetworkRolePropertyVal = getClonedObject(networkRolePropertyValue);
 
 269         connectionPoint.setNetwork_role(portMirroringNetworkRolePropertyVal);
 
 272     //Get NFC_Type from the binding requirement node
 
 273     if (Objects.nonNull(portNodeTemplate.getRequirements())) {
 
 274       Optional<List<RequirementAssignment>> requirementAssignment =
 
 275           DataModelUtil.getRequirementAssignment(portNodeTemplate.getRequirements(), ToscaConstants
 
 276               .BINDING_REQUIREMENT_ID);
 
 277       if (requirementAssignment.isPresent()) {
 
 278         RequirementAssignment bindingRequirementAssignment = requirementAssignment.get().get(0);
 
 279         String node = bindingRequirementAssignment.getNode();
 
 280         connectionPoint.setNfc_type(node);
 
 284     if (!connectionPoint.isEmpty()) {
 
 285       portMirroringCapabilityProperties.put(PORT_MIRRORING_CAPABILITY_CP_PROPERTY_NAME,
 
 287       DataModelUtil.addNodeTemplateCapability(portNodeTemplate,
 
 288           PORT_MIRRORING_CAPABILITY_ID, portMirroringCapabilityProperties, null);
 
 292   private void addGlobalTypeImport(ServiceTemplate serviceTemplate) {
 
 293     List<Map<String, Import>> imports = serviceTemplate.getImports();
 
 294     Map<String, Import> openecompIndexImport = new HashMap<>();
 
 295     openecompIndexImport.put("openecomp_index",
 
 296         HeatToToscaUtil.createServiceTemplateImport(globalTypesServiceTemplate
 
 297             .get("openecomp/_index.yml")));
 
 298     imports.add(openecompIndexImport);
 
 301   private boolean isPortNodeTemplate(String nodeType) {
 
 302     //Check if node corresponds to a concrete port node
 
 303     Set<String> portNodeTypes = getPortNodeTypes();
 
 304     return Objects.nonNull(nodeType)
 
 305         && portNodeTypes.contains(nodeType);
 
 308   private Set<String> getPortNodeTypes(){
 
 309     return new HashSet<>(Arrays.asList(ToscaNodeType.NEUTRON_PORT,
 
 310         ToscaNodeType.CONTRAILV2_VIRTUAL_MACHINE_INTERFACE,
 
 311         ToscaNodeType.CONTRAIL_PORT));
 
 314   private boolean isSubstitutableNodeTemplate(NodeTemplate nodeTemplate) {
 
 315     if (Objects.nonNull(nodeTemplate.getDirectives())) {
 
 316       return nodeTemplate.getDirectives().contains(ToscaConstants
 
 317           .NODE_TEMPLATE_DIRECTIVE_SUBSTITUTABLE);
 
 322   private boolean isInternalPort(String serviceTemplateFileName, String nodeTemplateId,
 
 323                                  NodeTemplate nodeTemplate) {
 
 324     return isAbstractInternalPort(serviceTemplateFileName, nodeTemplateId)
 
 325         || isConcreteInternalPort(nodeTemplate);
 
 328   private boolean isAbstractInternalPort(String serviceTemplateFileName, String nodeTemplateId) {
 
 329     //Check if port corresponds to an abstract internal port
 
 330     if (portNodeTemplateIdsFromAbstract.containsKey(serviceTemplateFileName)) {
 
 331       return portNodeTemplateIdsFromAbstract.get(serviceTemplateFileName).contains(nodeTemplateId);
 
 337   private boolean isConcreteInternalPort(NodeTemplate nodeTemplate) {
 
 338     //Check if node template contains a link requirement
 
 339     List<Map<String, RequirementAssignment>> requirements = nodeTemplate.getRequirements();
 
 340     if (Objects.nonNull(requirements)) {
 
 341       for (Map<String, RequirementAssignment> requirement : requirements) {
 
 342         String requirementId = requirement.keySet().iterator().next();
 
 343         if (requirementId.equals(ToscaConstants.LINK_REQUIREMENT_ID)) {