public List internalOrderResources()

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;
    }