diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TopologicalSort.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TopologicalSort.java
new file mode 100644
index 00000000000..9d2a78b416d
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TopologicalSort.java
@@ -0,0 +1,110 @@
+package org.eclipse.jetty.util;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+
+
+/**
+ * Topological Sort a list or array.
+ *
The algorithm has the additional characteristic that dependency sets are
+ * sorted by the original list order so that order is preserved when possible
+ * @param The type to be sorted.
+ */
+public class TopologicalSort
+{
+ private final Map> _dependencies = new HashMap<>();
+
+ public void addDependency(T dependent, T dependency)
+ {
+ Set set = _dependencies.get(dependent);
+ if (set==null)
+ {
+ set=new HashSet<>();
+ _dependencies.put(dependent,set);
+ }
+ set.add(dependency);
+ }
+
+ public void sort(T[] list)
+ {
+ List sorted = new ArrayList<>();
+ Set visited = new HashSet<>();
+ Comparator comparator = new InitialOrderComparitor<>(list);
+ for (T t : list)
+ visit(t,visited,sorted,comparator);
+
+ sorted.toArray(list);
+ }
+
+ public void sort(Collection list)
+ {
+ List sorted = new ArrayList<>();
+ Set visited = new HashSet<>();
+ Comparator comparator = new InitialOrderComparitor<>(list);
+
+ for (T t : list)
+ visit(t,visited,sorted,comparator);
+
+ list.clear();
+ list.addAll(sorted);
+ }
+
+ private void visit(T t, Set visited, List sorted,Comparator comparator)
+ {
+ if( !visited.contains(t) )
+ {
+ visited.add( t );
+
+ Set dependencies = _dependencies.get(t);
+ if (dependencies!=null)
+ {
+ SortedSet ordered_deps = new TreeSet<>(comparator);
+ ordered_deps.addAll(dependencies);
+ for (T d:ordered_deps)
+ visit(d,visited,sorted,comparator);
+ }
+ sorted.add(t);
+ }
+ else if (!sorted.contains(t))
+ throw new IllegalStateException("cyclic");
+ }
+
+ private static class InitialOrderComparitor implements Comparator
+ {
+ private final Map _indexes = new HashMap<>();
+ InitialOrderComparitor(T[] initial)
+ {
+ int i=0;
+ for (T t : initial)
+ _indexes.put(t,i++);
+ }
+
+ InitialOrderComparitor(Collection initial)
+ {
+ int i=0;
+ for (T t : initial)
+ _indexes.put(t,i++);
+ }
+
+ @Override
+ public int compare(T o1, T o2)
+ {
+ Integer i1=_indexes.get(o1);
+ Integer i2=_indexes.get(o2);
+ if (i1==null || i2==null || i1.equals(o2))
+ return 0;
+ if (i1 ts = new TopologicalSort<>();
+ ts.sort(s);
+
+ Assert.assertThat(s,Matchers.arrayContaining("D","E","C","B","A"));
+ }
+
+ @Test
+ public void testSimpleLinear()
+ {
+ String[] s = { "D","E","C","B","A" };
+ TopologicalSort ts = new TopologicalSort<>();
+ ts.addDependency("B","A");
+ ts.addDependency("C","B");
+ ts.addDependency("D","C");
+ ts.addDependency("E","D");
+
+ ts.sort(s);
+
+ Assert.assertThat(s,Matchers.arrayContaining("A","B","C","D","E"));
+ }
+
+ @Test
+ public void testDisjoint()
+ {
+ String[] s = { "A","C","B","CC","AA","BB"};
+
+ TopologicalSort ts = new TopologicalSort<>();
+ ts.addDependency("B","A");
+ ts.addDependency("C","B");
+ ts.addDependency("BB","AA");
+ ts.addDependency("CC","BB");
+
+ ts.sort(s);
+
+ Assert.assertThat(s,Matchers.arrayContaining("A","B","C","AA","BB","CC"));
+ }
+
+ @Test
+ public void testDisjointReversed()
+ {
+ String[] s = { "CC","AA","BB","A","C","B"};
+
+ TopologicalSort ts = new TopologicalSort<>();
+ ts.addDependency("B","A");
+ ts.addDependency("C","B");
+ ts.addDependency("BB","AA");
+ ts.addDependency("CC","BB");
+
+ ts.sort(s);
+
+ Assert.assertThat(s,Matchers.arrayContaining("AA","BB","CC","A","B","C"));
+ }
+
+ @Test
+ public void testDisjointMixed()
+ {
+ String[] s = { "CC","A","AA","C","BB","B"};
+
+ TopologicalSort ts = new TopologicalSort<>();
+ ts.addDependency("B","A");
+ ts.addDependency("C","B");
+ ts.addDependency("BB","AA");
+ ts.addDependency("CC","BB");
+
+ ts.sort(s);
+
+ // Check direct ordering
+ Assert.assertThat(indexOf(s,"A"),lessThan(indexOf(s,"B")));
+ Assert.assertThat(indexOf(s,"B"),lessThan(indexOf(s,"C")));
+ Assert.assertThat(indexOf(s,"AA"),lessThan(indexOf(s,"BB")));
+ Assert.assertThat(indexOf(s,"BB"),lessThan(indexOf(s,"CC")));
+ }
+
+ @Test
+ public void testTree()
+ {
+ String[] s = { "LeafA0","LeafB0","LeafA1","Root","BranchA","LeafB1","BranchB"};
+
+ TopologicalSort ts = new TopologicalSort<>();
+ ts.addDependency("BranchB","Root");
+ ts.addDependency("BranchA","Root");
+ ts.addDependency("LeafA1","BranchA");
+ ts.addDependency("LeafA0","BranchA");
+ ts.addDependency("LeafB0","BranchB");
+ ts.addDependency("LeafB1","BranchB");
+
+ ts.sort(s);
+
+ // Check direct ordering
+ Assert.assertThat(indexOf(s,"Root"),lessThan(indexOf(s,"BranchA")));
+ Assert.assertThat(indexOf(s,"Root"),lessThan(indexOf(s,"BranchB")));
+ Assert.assertThat(indexOf(s,"BranchA"),lessThan(indexOf(s,"LeafA0")));
+ Assert.assertThat(indexOf(s,"BranchA"),lessThan(indexOf(s,"LeafA1")));
+ Assert.assertThat(indexOf(s,"BranchB"),lessThan(indexOf(s,"LeafB0")));
+ Assert.assertThat(indexOf(s,"BranchB"),lessThan(indexOf(s,"LeafB1")));
+
+ // check remnant ordering of original list
+ Assert.assertThat(indexOf(s,"BranchA"),lessThan(indexOf(s,"BranchB")));
+ Assert.assertThat(indexOf(s,"LeafA0"),lessThan(indexOf(s,"LeafA1")));
+ Assert.assertThat(indexOf(s,"LeafB0"),lessThan(indexOf(s,"LeafB1")));
+ }
+
+ @Test
+ public void testPreserveOrder()
+ {
+ String[] s = { "Deep","Foobar","Wibble","Bozo","XXX","12345","Test"};
+
+ TopologicalSort ts = new TopologicalSort<>();
+ ts.addDependency("Deep","Test");
+ ts.addDependency("Deep","Wibble");
+ ts.addDependency("Deep","12345");
+ ts.addDependency("Deep","XXX");
+ ts.addDependency("Deep","Foobar");
+ ts.addDependency("Deep","Bozo");
+
+ ts.sort(s);
+ Assert.assertThat(s,Matchers.arrayContaining("Foobar","Wibble","Bozo","XXX","12345","Test","Deep"));
+ }
+
+ @Test
+ public void testSimpleLoop()
+ {
+ String[] s = { "A","B","C","D","E" };
+ TopologicalSort ts = new TopologicalSort<>();
+ ts.addDependency("B","A");
+ ts.addDependency("A","B");
+
+ try
+ {
+ ts.sort(s);
+ Assert.fail();
+ }
+ catch(IllegalStateException e)
+ {
+ Assert.assertThat(e.getMessage(),Matchers.containsString("cyclic"));
+ }
+ }
+
+ @Test
+ public void testDeepLoop()
+ {
+ String[] s = { "A","B","C","D","E" };
+ TopologicalSort ts = new TopologicalSort<>();
+ ts.addDependency("B","A");
+ ts.addDependency("C","B");
+ ts.addDependency("D","C");
+ ts.addDependency("E","D");
+ ts.addDependency("A","E");
+ try
+ {
+ ts.sort(s);
+ Assert.fail();
+ }
+ catch(IllegalStateException e)
+ {
+ Assert.assertThat(e.getMessage(),Matchers.containsString("cyclic"));
+ }
+ }
+
+ private int indexOf(String[] list,String s)
+ {
+ for (int i=0;i