in src/main/java/org/apache/sling/feature/resolver/FrameworkResolver.java [143:271]
public List<FeatureResource> internalOrderResources(List<Feature> features) throws IOException {
Map<Feature, FeatureResource> featureMap = new HashMap<>();
Map<FeatureResource, Feature> resourceMap = new HashMap<>();
for (Feature f : features) {
try {
FeatureResourceImpl fr = new FeatureResourceImpl(f);
resourceMap.put(fr, f);
featureMap.put(f, fr);
for (Artifact b : f.getBundles())
{
BundleDescriptor bd = getBundleDescriptor(artifactManager, b);
FeatureResource r = new BundleResourceImpl(bd, f);
resourceMap.put(r, f);
}
} catch (Exception ex) {
throw new IOException("Error processing feature: " + f.getLocation(), ex);
}
}
Map<String, FeatureResource> idVerMap = new HashMap<>();
for (FeatureResource fr : resourceMap.keySet()) {
idVerMap.put(fr.getId() + ":" + fr.getVersion(), fr);
}
// Add these too
Artifact lpa = new Artifact(ArtifactId.parse("org.apache.sling/org.apache.sling.launchpad.api/1.2.0"));
idVerMap.put("org.apache.sling.launchpad.api:1.2.0", new BundleResourceImpl(getBundleDescriptor(artifactManager, lpa), null));
idVerMap.put(framework.getSymbolicName() + ":" + framework.getVersion(), frameworkResource);
List<FeatureResource> orderedResources = new LinkedList<>();
try {
for (FeatureResource resource : resourceMap.keySet()) {
if (orderedResources.contains(resource)) {
// Already handled
continue;
}
Map<Resource, List<Wire>> deps = resolver.resolve(new ResolveContextImpl(resource, idVerMap.values()));
for (Map.Entry<Resource, List<Wire>> entry : deps.entrySet()) {
if (resource.equals(entry.getKey()))
continue;
Resource depResource = entry.getKey();
FeatureResource curResource = getFeatureResource(depResource, idVerMap);
if (curResource == null)
continue;
if (!orderedResources.contains(curResource)) {
orderedResources.add(curResource);
}
for (Wire w : entry.getValue()) {
FeatureResource provBundle = getFeatureResource(w.getProvider(), idVerMap);
if (provBundle == null)
continue;
int curBundleIdx = orderedResources.indexOf(curResource);
int newBundleIdx = orderedResources.indexOf(provBundle);
if (newBundleIdx >= 0) {
if (curBundleIdx < newBundleIdx) {
// If the list already contains the providing but after the current bundle, remove it there to move it before the current bundle
orderedResources.remove(provBundle);
} else {
// If the providing bundle is already before the current bundle, then no need to change anything
continue;
}
}
orderedResources.add(curBundleIdx, provBundle);
}
}
// All of the dependencies of the resource have been added, now add the resource itself
if (!orderedResources.contains(resource)) {
Feature associatedFeature = resource.getFeature();
if (resource.equals(featureMap.get(associatedFeature))) {
// The resource is a feature resource, don't add this one by itself.
}
else {
orderedResources.add(resource);
}
}
}
} catch (ResolutionException e) {
throw new RuntimeException(e);
}
// Sort the fragments so that fragments are started before the host bundle
for (int i=0; i<orderedResources.size(); i++) {
Resource r = orderedResources.get(i);
List<Requirement> reqs = r.getRequirements(HostNamespace.HOST_NAMESPACE);
if (reqs.size() > 0) {
// This is a fragment
Requirement req = reqs.iterator().next(); // TODO handle more host requirements
String bsn = req.getAttributes().get(HostNamespace.HOST_NAMESPACE).toString(); // TODO this is not valid, should obtain from filter
// system bundle is already started, no need to reorder here
if ( Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(bsn)) {
continue;
}
int idx = getBundleIndex(orderedResources, bsn); // TODO check for filter too
if (idx < i) {
// the fragment is after the host, and should be moved to be before the host
FeatureResource frag = orderedResources.remove(i);
orderedResources.add(idx, frag);
}
}
}
// Add the features at the appropriate place to the ordered resources list
for (int i=0; i<orderedResources.size(); i++) {
FeatureResource r = orderedResources.get(i);
FeatureResource associatedFeature = featureMap.get(r.getFeature());
if (associatedFeature == null)
continue;
int idx = orderedResources.indexOf(associatedFeature);
if (idx > i) {
orderedResources.remove(idx);
orderedResources.add(i, associatedFeature);
} else if (idx == -1) {
orderedResources.add(i, associatedFeature);
}
}
// If the framework shows up as a dependency, remove it as it's always there
orderedResources.remove(frameworkResource);
return orderedResources;
}