package com.hubspot.blazar.base; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.Stack; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; public class DependencyGraph { private final Map<Integer, Set<Integer>> transitiveReduction; private final List<Integer> topologicalSort; @JsonCreator public DependencyGraph(@JsonProperty("transitiveReduction") Map<Integer, Set<Integer>> transitiveReduction, @JsonProperty("topologicalSort") List<Integer> topologicalSort) { this.transitiveReduction = transitiveReduction; this.topologicalSort = topologicalSort; } public Map<Integer, Set<Integer>> getTransitiveReduction() { return transitiveReduction; } public List<Integer> getTopologicalSort() { return topologicalSort; } public Set<Integer> incomingVertices(int moduleId) { Set<Integer> incomingVertices = new HashSet<>(); for (Entry<Integer, Set<Integer>> edgeSet : transitiveReduction.entrySet()) { int source = edgeSet.getKey(); for (int target : edgeSet.getValue()) { if (target == moduleId) { incomingVertices.add(source); } } } return incomingVertices; } public Set<Integer> getAllUpstreamNodes(int moduleId) { Stack<Integer> stack = new Stack<>(); stack.push(moduleId); Set<Integer> seen = new HashSet<>(); Set<Integer> allIncoming = new HashSet<>(); while (!stack.empty()) { int i = stack.pop(); if (seen.contains(i)) { continue; } seen.add(i); Set<Integer> incoming = incomingVertices(i); allIncoming.addAll(incoming); for (int each : incoming) { if (seen.contains(each)) { continue; } stack.add(each); } } return allIncoming; } public List<Module> orderByTopologicalSort(Set<Module> modules) { List<Module> moduleList = Lists.newArrayList(modules); // We want to sort by their build order (the topo-sort), so we compare their indices in that list moduleList.sort(Comparator.comparingInt(module -> topologicalSort.indexOf(module.getId().get()))); return ImmutableList.copyOf(moduleList); } public Set<Integer> reachableVertices(int moduleId) { Set<Integer> reachableVertices = new HashSet<>(); for (int vertex : outgoingVertices(moduleId)) { reachableVertices.add(vertex); reachableVertices.addAll(reachableVertices(vertex)); } return reachableVertices; } public Set<Integer> outgoingVertices(int moduleId) { return MoreObjects.firstNonNull(transitiveReduction.get(moduleId), Collections.<Integer>emptySet()); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } DependencyGraph that = (DependencyGraph) o; return java.util.Objects.equals(transitiveReduction, that.transitiveReduction) && java.util.Objects.equals(topologicalSort, that.topologicalSort); } @Override public int hashCode() { return java.util.Objects.hash(transitiveReduction, topologicalSort); } @Override public String toString() { return transitiveReduction.toString(); } }