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 org.elasticsearch.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; } } }