content: package alien4cloud.topology.validation;
  
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import javax.annotation.Resource;
  
  import org.alien4cloud.tosca.catalog.index.IToscaTypeSearchService;
  import org.alien4cloud.tosca.model.templates.NodeTemplate;
  import org.alien4cloud.tosca.model.templates.RelationshipTemplate;
  import org.alien4cloud.tosca.model.templates.Topology;
  import org.alien4cloud.tosca.model.types.AbstractInheritableToscaType;
  import org.alien4cloud.tosca.model.types.RelationshipType;
  import com.google.common.collect.Sets;
  import org.springframework.stereotype.Component;
  
  import com.google.common.collect.Lists;
  import com.google.common.collect.Maps;
  
  import alien4cloud.exception.NotFoundException;
  import alien4cloud.topology.task.AbstractRelationshipTask;
  import alien4cloud.topology.task.TaskCode;
  
  /**
   * Performs validation by checking that no relationships in a topology are abstract (and cannot be instanciated).
   */
  @Component
  public class TopologyAbstractRelationshipValidationService {
      @Resource
      private IToscaTypeSearchService toscaTypeSearchService;
  
      /**
       * Checks that no relationships in a topology are abstract (and cannot be instanciated).
       *
       * @param topology The topology to validate.
       * @return A list tasks to be done to make this topology valid.
       */
      public List<AbstractRelationshipTask> validateAbstractRelationships(Topology topology) {
          Map<String, RelationshipType[]> abstractIndexedRelationshipTypes = getIndexedRelationshipTypesFromTopology(topology, true);
          return getTaskListFromMapArray(abstractIndexedRelationshipTypes, TaskCode.IMPLEMENT_RELATIONSHIP);
      }
  
      /**
       * Get the relationships from a topology
       *
       * @param topology topology to be validated
       * @param abstractOnes if only abstract ones should be retrieved
       * @return a map containing node template id --> list of relationship type that this node references
       */
      private Map<String, RelationshipType[]> getIndexedRelationshipTypesFromTopology(Topology topology, Boolean abstractOnes) {
          Map<String, RelationshipType[]> indexedRelationshipTypesMap = Maps.newHashMap();
          if (topology.getNodeTemplates() == null) {
              return indexedRelationshipTypesMap;
          }
          for (Map.Entry<String, NodeTemplate> template : topology.getNodeTemplates().entrySet()) {
              if (template.getValue().getRelationships() == null) {
                  continue;
              }
  
              Set<RelationshipType> indexedRelationshipTypes = Sets.newHashSet();
              for (RelationshipTemplate relTemplate : template.getValue().getRelationships().values()) {
                  RelationshipType indexedRelationshipType = toscaTypeSearchService.getElementInDependencies(RelationshipType.class, relTemplate.getType(),
                          topology.getDependencies());
                  if (indexedRelationshipType != null) {
                      if (abstractOnes == null || abstractOnes.equals(indexedRelationshipType.isAbstract())) {
                          indexedRelationshipTypes.add(indexedRelationshipType);
                      }
                  } else {
                      throw new NotFoundException("Relationship Type [" + relTemplate.getType() + "] cannot be found");
                  }
              }
              if (indexedRelationshipTypes.size() > 0) {
                  indexedRelationshipTypesMap.put(template.getKey(), indexedRelationshipTypes.toArray(new RelationshipType[indexedRelationshipTypes.size()]));
              }
  
          }
          return indexedRelationshipTypesMap;
      }
  
      /**
       * Constructs a TopologyTask list given a Map (node template name => component) and the code
       */
      private <T extends AbstractInheritableToscaType> List<AbstractRelationshipTask> getTaskListFromMapArray(Map<String, T[]> components, TaskCode taskCode) {
          List<AbstractRelationshipTask> taskList = Lists.newArrayList();
          for (Map.Entry<String, T[]> entry : components.entrySet()) {
              for (AbstractInheritableToscaType compo : entry.getValue()) {
                  AbstractRelationshipTask task = new AbstractRelationshipTask();
                  task.setNodeTemplateName(entry.getKey());
                  task.setComponent(compo);
                  task.setCode(taskCode);
                  taskList.add(task);
              }
          }
          if (taskList.isEmpty()) {
              return null;
          } else {
              return taskList;
          }
      }
  }
  