blob: 374c9701ce87b1bb963516d9a208bfd3de6126a9 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.webapp;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import org.eclipse.jetty.util.TopologicalSort;
import org.eclipse.jetty.util.resource.Resource;
/**
* Relative Fragment Ordering
* <p>Uses a {@link TopologicalSort} to order the fragments.</p>
*/
public class RelativeOrdering implements Ordering
{
protected MetaData _metaData;
public RelativeOrdering (MetaData metaData)
{
_metaData = metaData;
}
@Override
public List<Resource> order(List<Resource> jars)
{
TopologicalSort<Resource> sort = new TopologicalSort<>();
List<Resource> sorted = new ArrayList<>(jars);
Set<Resource> others = new HashSet<>();
Set<Resource> before_others = new HashSet<>();
Set<Resource> after_others = new HashSet<>();
// Pass 1: split the jars into 'before others', 'others' or 'after others'
for (Resource jar : jars)
{
FragmentDescriptor fragment=_metaData.getFragment(jar);
if (fragment == null)
others.add(jar);
else
{
switch (fragment.getOtherType())
{
case None:
others.add(jar);
break;
case Before:
before_others.add(jar);
break;
case After:
after_others.add(jar);
break;
}
}
}
// Pass 2: Add sort dependencies for each jar
Set<Resource> referenced = new HashSet<>();
for (Resource jar : jars)
{
FragmentDescriptor fragment=_metaData.getFragment(jar);
if (fragment != null)
{
// Add each explicit 'after' ordering as a sort dependency
// and remember that the dependency has been referenced.
for (String name: fragment.getAfters())
{
Resource after=_metaData.getJarForFragment(name);
sort.addDependency(jar,after);
referenced.add(after);
}
// Add each explicit 'before' ordering as a sort dependency
// and remember that the dependency has been referenced.
for (String name: fragment.getBefores())
{
Resource before=_metaData.getJarForFragment(name);
sort.addDependency(before,jar);
referenced.add(before);
}
// handle the others
switch (fragment.getOtherType())
{
case None:
break;
case Before:
// Add a dependency on this jar from all
// jars in the 'others' and 'after others' sets, but
// exclude any jars we have already explicitly
// referenced above.
Consumer<Resource> add_before = other ->
{
if (!referenced.contains(other))
sort.addDependency(other,jar);
};
others.forEach(add_before);
after_others.forEach(add_before);
break;
case After:
// Add a dependency from this jar to all
// jars in the 'before others' and 'others' sets, but
// exclude any jars we have already explicitly
// referenced above.
Consumer<Resource> add_after = other ->
{
if (!referenced.contains(other))
sort.addDependency(jar,other);
};
before_others.forEach(add_after);
others.forEach(add_after);
break;
}
}
referenced.clear();
}
// sort the jars according to the added dependencies
sort.sort(sorted);
return sorted;
}
}