Program: 62399
Project: 62399
Buggy source:
/** 
 * Process node substitution for the deployment topology
 * @param deploymentTopology the deployment topology to process substitution
 */
public void processNodesSubstitution(DeploymentTopology deploymentTopology,Map<String,NodeTemplate> nodesToMergeProperties){
  if (MapUtils.isEmpty(deploymentTopology.getLocationGroups())) {
    return;
  }
  deploymentTopology.getDependencies().addAll(deploymentTopology.getLocationDependencies());
  Map<String,List<LocationResourceTemplate>> availableSubstitutions=getAvailableSubstitutions(deploymentTopology.getNodeTemplates(),deploymentTopology.getDependencies(),deploymentTopology.getLocationGroups());
  Map<String,Set<String>> availableSubstitutionsIds=Maps.newHashMap();
  for (  Map.Entry<String,List<LocationResourceTemplate>> availableSubstitutionEntry : availableSubstitutions.entrySet()) {
    Set<String> ids=Sets.newHashSet();
    for (    LocationResourceTemplate availableSubstitution : availableSubstitutionEntry.getValue()) {
      ids.add(availableSubstitution.getId());
    }
    availableSubstitutionsIds.put(availableSubstitutionEntry.getKey(),ids);
  }
  Map<String,String> substitutedNodes=deploymentTopology.getSubstitutedNodes();
  removeUnsynchronizedSubstitutions(deploymentTopology,substitutedNodes,availableSubstitutions);
  Iterator<Entry<String,NodeTemplate>> originalNodesIter=deploymentTopology.getOriginalNodes().entrySet().iterator();
  while (originalNodesIter.hasNext()) {
    Entry<String,NodeTemplate> next=originalNodesIter.next();
    if (!availableSubstitutions.containsKey(next.getKey())) {
      originalNodesIter.remove();
    }
  }
  for (  Map.Entry<String,List<LocationResourceTemplate>> entry : availableSubstitutions.entrySet()) {
    if (!substitutedNodes.containsKey(entry.getKey())) {
      deploymentTopology.getOriginalNodes().put(entry.getKey(),deploymentTopology.getNodeTemplates().get(entry.getKey()));
      if (!entry.getValue().isEmpty()) {
        substitutedNodes.put(entry.getKey(),entry.getValue().iterator().next().getId());
      }
    }
  }
  deploymentTopology.setSubstitutedNodes(substitutedNodes);
  for (  Map.Entry<String,String> substitutedNodeEntry : substitutedNodes.entrySet()) {
    NodeTemplate locationNode=locationResourceService.getOrFail(substitutedNodeEntry.getValue()).getTemplate();
    NodeTemplate abstractTopologyNode=deploymentTopology.getNodeTemplates().put(substitutedNodeEntry.getKey(),locationNode);
    NodeTemplate previousNode=null;
    if (nodesToMergeProperties != null) {
      previousNode=nodesToMergeProperties.get(substitutedNodeEntry.getKey());
    }
    locationNode.setName(abstractTopologyNode.getName());
    locationNode.setRelationships(abstractTopologyNode.getRelationships());
    if (MapUtils.isNotEmpty(locationNode.getProperties())) {
      Set<String> keysToConsider=locationNode.getProperties().keySet();
      Map<String,AbstractPropertyValue> mergedProperties=Maps.newLinkedHashMap();
      if (previousNode != null && MapUtils.isNotEmpty(previousNode.getProperties())) {
        PropertyUtil.mergeProperties(previousNode.getProperties(),mergedProperties,keysToConsider);
      }
      if (MapUtils.isNotEmpty(locationNode.getProperties())) {
        PropertyUtil.mergeProperties(locationNode.getProperties(),mergedProperties,keysToConsider);
      }
      if (MapUtils.isNotEmpty(abstractTopologyNode.getProperties())) {
        PropertyUtil.mergeProperties(abstractTopologyNode.getProperties(),mergedProperties,keysToConsider);
      }
      locationNode.setProperties(mergedProperties);
    }
    if (MapUtils.isNotEmpty(locationNode.getCapabilities())) {
      for (      Map.Entry<String,Capability> locationCapabilityEntry : locationNode.getCapabilities().entrySet()) {
        Capability locationCapability=locationCapabilityEntry.getValue();
        if (MapUtils.isEmpty(locationCapability.getProperties())) {
          continue;
        }
        Set<String> keysToConsider=locationCapability.getProperties().keySet();
        Map<String,AbstractPropertyValue> mergedCapabilityProperties=Maps.newLinkedHashMap();
        Capability previousCapability=null;
        if (previousNode != null && MapUtils.isNotEmpty(previousNode.getCapabilities())) {
          previousCapability=previousNode.getCapabilities().get(locationCapabilityEntry.getKey());
        }
        if (previousCapability != null && MapUtils.isNotEmpty(previousCapability.getProperties())) {
          PropertyUtil.mergeProperties(previousCapability.getProperties(),mergedCapabilityProperties,keysToConsider);
        }
        PropertyUtil.mergeProperties(locationCapability.getProperties(),mergedCapabilityProperties,keysToConsider);
        Capability abstractCapability=null;
        if (MapUtils.isNotEmpty(abstractTopologyNode.getCapabilities())) {
          abstractCapability=abstractTopologyNode.getCapabilities().get(locationCapabilityEntry.getKey());
        }
        if (abstractCapability != null && MapUtils.isNotEmpty(abstractCapability.getProperties())) {
          PropertyUtil.mergeProperties(abstractCapability.getProperties(),mergedCapabilityProperties,keysToConsider);
        }
        locationCapability.setProperties(mergedCapabilityProperties);
      }
    }
  }
}

Fixed version (ground truth):
/** 
 * This method updates the node substitution choices and default selections for a given deployment topology.
 * @param deploymentTopology The deployment topology in which to save substitutions / deploymentTopology.getNodeTemplates() are the nodes from the originaltopology.
 * @param nodesToMergeProperties The node that where substituted previously with specific configurations from deployment user.
 */
public void processNodesSubstitution(DeploymentTopology deploymentTopology,Map<String,NodeTemplate> nodesToMergeProperties){
  if (MapUtils.isEmpty(deploymentTopology.getLocationGroups())) {
    return;
  }
  deploymentTopology.getDependencies().addAll(deploymentTopology.getLocationDependencies());
  Map<String,List<LocationResourceTemplate>> availableSubstitutions=getAvailableSubstitutions(deploymentTopology.getNodeTemplates(),deploymentTopology.getDependencies(),deploymentTopology.getLocationGroups());
  Map<String,Set<String>> availableSubstitutionsIds=Maps.newHashMap();
  for (  Map.Entry<String,List<LocationResourceTemplate>> availableSubstitutionEntry : availableSubstitutions.entrySet()) {
    Set<String> ids=Sets.newHashSet();
    for (    LocationResourceTemplate availableSubstitution : availableSubstitutionEntry.getValue()) {
      ids.add(availableSubstitution.getId());
    }
    availableSubstitutionsIds.put(availableSubstitutionEntry.getKey(),ids);
  }
  Map<String,String> substitutedNodes=deploymentTopology.getSubstitutedNodes();
  removeUnsynchronizedSubstitutions(deploymentTopology,substitutedNodes,availableSubstitutions);
  Iterator<Entry<String,NodeTemplate>> originalNodesIter=deploymentTopology.getOriginalNodes().entrySet().iterator();
  while (originalNodesIter.hasNext()) {
    Entry<String,NodeTemplate> next=originalNodesIter.next();
    if (!availableSubstitutions.containsKey(next.getKey())) {
      originalNodesIter.remove();
    }
 else {
      next.setValue(deploymentTopology.getNodeTemplates().get(next.getKey()));
    }
  }
  for (  Map.Entry<String,List<LocationResourceTemplate>> entry : availableSubstitutions.entrySet()) {
    if (!substitutedNodes.containsKey(entry.getKey())) {
      deploymentTopology.getOriginalNodes().put(entry.getKey(),deploymentTopology.getNodeTemplates().get(entry.getKey()));
      if (!entry.getValue().isEmpty()) {
        substitutedNodes.put(entry.getKey(),entry.getValue().iterator().next().getId());
      }
    }
  }
  deploymentTopology.setSubstitutedNodes(substitutedNodes);
  for (  Map.Entry<String,String> substitutedNodeEntry : substitutedNodes.entrySet()) {
    NodeTemplate locationNode=locationResourceService.getOrFail(substitutedNodeEntry.getValue()).getTemplate();
    NodeTemplate abstractTopologyNode=deploymentTopology.getNodeTemplates().put(substitutedNodeEntry.getKey(),locationNode);
    NodeTemplate previousNode=null;
    if (nodesToMergeProperties != null) {
      previousNode=nodesToMergeProperties.get(substitutedNodeEntry.getKey());
    }
    locationNode.setName(abstractTopologyNode.getName());
    locationNode.setRelationships(abstractTopologyNode.getRelationships());
    if (MapUtils.isNotEmpty(locationNode.getProperties())) {
      Set<String> keysToConsider=locationNode.getProperties().keySet();
      Map<String,AbstractPropertyValue> mergedProperties=Maps.newLinkedHashMap();
      if (previousNode != null && MapUtils.isNotEmpty(previousNode.getProperties())) {
        PropertyUtil.mergeProperties(previousNode.getProperties(),mergedProperties,keysToConsider);
      }
      if (MapUtils.isNotEmpty(abstractTopologyNode.getProperties())) {
        PropertyUtil.mergeProperties(abstractTopologyNode.getProperties(),mergedProperties,keysToConsider);
      }
      if (MapUtils.isNotEmpty(locationNode.getProperties())) {
        PropertyUtil.mergeProperties(locationNode.getProperties(),mergedProperties,keysToConsider);
      }
      locationNode.setProperties(mergedProperties);
    }
    if (MapUtils.isNotEmpty(locationNode.getCapabilities())) {
      for (      Map.Entry<String,Capability> locationCapabilityEntry : locationNode.getCapabilities().entrySet()) {
        Capability locationCapability=locationCapabilityEntry.getValue();
        if (MapUtils.isEmpty(locationCapability.getProperties())) {
          continue;
        }
        Set<String> keysToConsider=locationCapability.getProperties().keySet();
        Map<String,AbstractPropertyValue> mergedCapabilityProperties=Maps.newLinkedHashMap();
        Capability previousCapability=null;
        if (previousNode != null && MapUtils.isNotEmpty(previousNode.getCapabilities())) {
          previousCapability=previousNode.getCapabilities().get(locationCapabilityEntry.getKey());
        }
        if (previousCapability != null && MapUtils.isNotEmpty(previousCapability.getProperties())) {
          PropertyUtil.mergeProperties(previousCapability.getProperties(),mergedCapabilityProperties,keysToConsider);
        }
        PropertyUtil.mergeProperties(locationCapability.getProperties(),mergedCapabilityProperties,keysToConsider);
        Capability abstractCapability=null;
        if (MapUtils.isNotEmpty(abstractTopologyNode.getCapabilities())) {
          abstractCapability=abstractTopologyNode.getCapabilities().get(locationCapabilityEntry.getKey());
        }
        if (abstractCapability != null && MapUtils.isNotEmpty(abstractCapability.getProperties())) {
          PropertyUtil.mergeProperties(abstractCapability.getProperties(),mergedCapabilityProperties,keysToConsider);
        }
        locationCapability.setProperties(mergedCapabilityProperties);
      }
    }
  }
}