package alien4cloud.model.components; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.alien4cloud.tosca.model.definitions.CapabilityDefinition; import org.alien4cloud.tosca.model.definitions.Interface; import org.alien4cloud.tosca.model.definitions.Operation; import org.alien4cloud.tosca.model.definitions.RequirementDefinition; import org.alien4cloud.tosca.model.types.AbstractInheritableToscaType; import org.alien4cloud.tosca.model.types.NodeType; import org.alien4cloud.tosca.model.types.RelationshipType; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import alien4cloud.exception.IndexingServiceException; import alien4cloud.model.common.Tag; import alien4cloud.utils.CollectionUtils; /** * Utils class for Indexed(DAO Object Types) Model. */ public final class IndexedModelUtils { public static final String TOSCA_INDEXED_SUMMARY_KEY = "summary"; // make sure this class is not instantiated private IndexedModelUtils() { } /** * This utility method returns an ordered {@link AbstractInheritableToscaType} collection. The parent elements will be before * the children elements * This utility method returns an ordered {@link AbstractInheritableToscaType} collection. The parent elements will be before the children elements * * @param elementsByIdMap map of {@link AbstractInheritableToscaType} by id * @return */ public static <T extends AbstractInheritableToscaType> List<T> orderByDerivedFromHierarchy(final Map<String, T> elementsByIdMap) { if (elementsByIdMap == null) { return null; } List<T> orderedElements = new ArrayList<T>(elementsByIdMap.values()); final Map<String, Integer> elementsLevelMap = Maps.newHashMap(); for (AbstractInheritableToscaType element : orderedElements) { AbstractInheritableToscaType parent = element; int levelCount = 0; while (true) { if (parent.getDerivedFrom() == null || parent.getDerivedFrom().isEmpty()) { break; } AbstractInheritableToscaType oldParent = parent; parent = elementsByIdMap.get(parent.getDerivedFrom().get(0)); if (parent == null) { break; } if (oldParent.equals(parent)) { // this elements is inheriting from it-self --> error // This error must have been normally detected in the validation phase and so here it means that it's a bug in our code of validation throw new IndexingServiceException(parent.getElementId() + " is parent of it-self, bug in csar validation service"); } levelCount++; } elementsLevelMap.put(element.getElementId(), levelCount); } Collections.sort(orderedElements, (left, right) -> elementsLevelMap.get(left.getElementId()).compareTo(elementsLevelMap.get(right.getElementId()))); return orderedElements; } public static void mergeInheritableIndex(AbstractInheritableToscaType from, AbstractInheritableToscaType to) { if (from.getDerivedFrom() != null) { // use a linked HashSet so we don't add multiple elements more than once. LinkedHashSet<String> derivedFromSet = new LinkedHashSet<String>(); if (to.getDerivedFrom() != null) { derivedFromSet.addAll(to.getDerivedFrom()); } if (from.getDerivedFrom() != null) { derivedFromSet.addAll(from.getDerivedFrom()); } to.setDerivedFrom(new ArrayList<String>(derivedFromSet)); } if (from.getTags() != null) { if (to.getTags() == null) { to.setTags(Lists.<Tag> newArrayList()); to.getTags().addAll(from.getTags()); } else { // copy non existing tags from the parent "from" for (Tag tag : from.getTags()) { if (!to.getTags().contains(tag)) { to.getTags().add(tag); } } } } mergePropertiesAndAttributes(from, to); if (from instanceof NodeType && to instanceof NodeType) { mergeNodeType((NodeType) from, (NodeType) to); } if (from instanceof RelationshipType && to instanceof RelationshipType) { mergeRelationshipType((RelationshipType) from, (RelationshipType) to); } } private static void mergePropertiesAndAttributes(AbstractInheritableToscaType from, AbstractInheritableToscaType to) { if (from.getProperties() != null) { to.setProperties(CollectionUtils.merge(from.getProperties(), to.getProperties(), false)); } } private static void mergeNodeType(NodeType from, NodeType to) { to.setCapabilities(CollectionUtils.merge(from.getCapabilities(), to.getCapabilities())); to.setRequirements(CollectionUtils.merge(from.getRequirements(), to.getRequirements())); to.setInterfaces(mergeInterfaces(from.getInterfaces(), to.getInterfaces())); to.setArtifacts(CollectionUtils.merge(from.getArtifacts(), to.getArtifacts(), false)); if (from.getAttributes() != null) { to.setAttributes(CollectionUtils.merge(from.getAttributes(), to.getAttributes(), false)); } } private static void mergeRelationshipType(RelationshipType from, RelationshipType to) { if (to.getValidSources() == null) { to.setValidSources(from.getValidSources()); } if (to.getValidTargets() == null) { to.setValidTargets(from.getValidTargets()); } if (from.getAttributes() != null) { to.setAttributes(CollectionUtils.merge(from.getAttributes(), to.getAttributes(), false)); } to.setInterfaces(mergeInterfaces(from.getInterfaces(), to.getInterfaces())); to.setArtifacts(CollectionUtils.merge(from.getArtifacts(), to.getArtifacts(), false)); } /** * Merge interface & operations: all 'from' interfaces will be merged into 'to' interfaces. * <p> * 'from' entries are added to 'to' entries if not exist (so entries in 'to' are preserved). */ public static Map<String, Interface> mergeInterfaces(Map<String, Interface> from, Map<String, Interface> to) { Map<String, Interface> target = to; if (target == null) { return from; } if (from == null) { return target; } for (Entry<String, Interface> fromEntry : from.entrySet()) { Interface toInterface = target.get(fromEntry.getKey()); Interface fromInterface = fromEntry.getValue(); if (toInterface == null) { // the target doesn't contain this key, just put it target.put(fromEntry.getKey(), fromEntry.getValue()); } else { // the target already have this entry, so we'll compare operations in detail Map<String, Operation> toOperations = toInterface.getOperations(); if (toOperations == null) { toInterface.setOperations(fromInterface.getOperations()); } else if (fromInterface.getOperations() != null) { for (Entry<String, Operation> fromOperationEntry : fromInterface.getOperations().entrySet()) { if (!toOperations.containsKey(fromOperationEntry.getKey())) { toOperations.put(fromOperationEntry.getKey(), fromOperationEntry.getValue()); } } } } } return target; } public static CapabilityDefinition getCapabilityDefinitionById(List<CapabilityDefinition> list, String id) { if (list != null) { for (CapabilityDefinition cd : list) { if (cd.getId().equals(id)) { return cd; } } } return null; } public static RequirementDefinition getRequirementDefinitionById(List<RequirementDefinition> list, String id) { for (RequirementDefinition cd : list) { if (cd.getId().equals(id)) { return cd; } } return null; } }