package knorxx.framework.generator.order; import com.google.common.base.Joiner; import com.google.common.base.Optional; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.jgrapht.alg.CycleDetector; import org.jgrapht.graph.DefaultEdge; import org.jgrapht.graph.SimpleDirectedGraph; import org.jgrapht.traverse.TopologicalOrderIterator; /** * * @author sj */ public abstract class OrderSorter { private Optional<OrderSorter> nextCollector = Optional.absent(); public OrderSorter() { } public OrderSorter(OrderSorter nextCollector) { this.nextCollector = Optional.of(nextCollector); } public Set<OrderConstraint> getConstraints(List<Class<?>> classes) { Set<OrderConstraint> result = getConstraintsInternal(classes); if (nextCollector.isPresent()) { result.addAll(nextCollector.get().getConstraintsInternal(classes)); } return result; } protected abstract Set<OrderConstraint> getConstraintsInternal(List<Class<?>> classes); public List<String> sort(List<Class<?>> classes) throws OrderSortCycleException { List<String> result = new ArrayList<>(); SimpleDirectedGraph<String, DefaultEdge> graph = new SimpleDirectedGraph<>(DefaultEdge.class); for (OrderConstraint orderConstraint : getConstraints(classes)) { graph.addVertex(orderConstraint.getFirst()); graph.addVertex(orderConstraint.getSecond()); graph.addEdge(orderConstraint.getFirst(), orderConstraint.getSecond()); } CycleDetector<String, DefaultEdge> cycleDetector = new CycleDetector<>(graph); if(!cycleDetector.detectCycles()) { for (TopologicalOrderIterator<String, DefaultEdge> iterator = new TopologicalOrderIterator<>(graph); iterator.hasNext();) { result.add(iterator.next()); } } else { String cycles = Joiner.on(", ").join(cycleDetector.findCycles()); throw new OrderSortCycleException("The given order constraints contain (at least one) cycle. Cycles can only " + "be caused by static references because we have single inherintance only in Java (involved classes: '" + cycles + "')."); } return result; } }