public ChainSpecification(ComponentId componentId, Inheritance inheritance, Collection<Phase> phases, Set<ComponentSpecification> componentReferences) { assertNotNull(componentId, inheritance, phases, componentReferences); if (componentsByName(componentReferences).size() != componentReferences.size()) throw new RuntimeException("Two components with the same name are specified in '" + componentId + "', but name must be unique inside a given chain."); this.componentId = componentId; this.inheritance = inheritance; this.phases = copyPhasesImmutable(phases); this.componentReferences = ImmutableSet.copyOf( filterByComponentSpecification(componentReferences, inheritance.excludedComponents)); }
/** * @param allChainSpecifications resolves ChainSpecifications from ComponentSpecifications * as given in the inheritance fields. * @param path tracks which chains are used in each recursive invocation of flatten, used for detecting cycles. * @return ChainSpecification directly containing all the component references and phases of the inherited chains. */ private ChainSpecification flatten(Resolver<ChainSpecification> allChainSpecifications, Deque<ComponentId> path) { path.push(componentId); //if this turns out to be a bottleneck(which I seriously doubt), please add memoization Map<String, ComponentSpecification> resultingComponents = componentsByName(componentReferences); Map<String, Phase> resultingPhases = new LinkedHashMap<>(phases); for (ComponentSpecification inheritedChainSpecification : inheritance.chainSpecifications) { ChainSpecification inheritedChain = resolveChain(path, allChainSpecifications, inheritedChainSpecification). flatten(allChainSpecifications, path); mergeInto(resultingComponents, filterByComponentSpecification( filterByName(inheritedChain.componentReferences, names(componentReferences)), inheritance.excludedComponents)); mergeInto(resultingPhases, inheritedChain.phases); } path.pop(); return new ChainSpecification(componentId, inheritance.flattened(), resultingPhases.values(), new LinkedHashSet<>(resultingComponents.values())); }