List<WrappedResource> hostResources = new ArrayList<WrappedResource>();
List<Resource> unselectedFragments = new ArrayList<Resource>();
for (Entry<Capability, Map<String, Map<Version, List<Requirement>>>> hostEntry : hostFragments.entrySet())
{
// Step 1
Capability hostCap = hostEntry.getKey();
Map<String, Map<Version, List<Requirement>>> fragments =
hostEntry.getValue();
List<Resource> selectedFragments = new ArrayList<Resource>();
for (Entry<String, Map<Version, List<Requirement>>> fragEntry
: fragments.entrySet())
{
boolean isFirst = true;
for (Entry<Version, List<Requirement>> versionEntry
: fragEntry.getValue().entrySet())
{
for (Requirement hostReq : versionEntry.getValue())
{
// Selecting the first fragment in each entry, which
// is equivalent to selecting the highest version of
// each fragment with a given symbolic name.
if (isFirst)
{
selectedFragments.add(hostReq.getResource());
isFirst = false;
}
// For any fragment that wasn't selected, remove the
// current host as a potential host for it and remove it
// as a dependent on the host. If there are no more
// potential hosts for the fragment, then mark it as
// unselected for later removal.
else
{
m_dependentMap.get(hostCap).remove(hostReq);
List<Capability> hosts = m_candidateMap.get(hostReq);
hosts.remove(hostCap);
if (hosts.isEmpty())
{
unselectedFragments.add(hostReq.getResource());
}
}
}
}
}
// Step 2
WrappedResource wrappedHost =
new WrappedResource(hostCap.getResource(), selectedFragments);
hostResources.add(wrappedHost);
m_allWrappedHosts.put(hostCap.getResource(), wrappedHost);
}
// Step 3
for (Resource fragment : unselectedFragments)
{
removeResource(fragment,
new ResolutionException(
"Fragment was not selected for attachment: " + fragment));
}
// Step 4
for (WrappedResource hostResource : hostResources)
{
// Replaces capabilities from fragments with the capabilities
// from the merged host.
for (Capability c : hostResource.getCapabilities(null))
{
// Don't replace the host capability, since the fragment will
// really be attached to the original host, not the wrapper.
if (!c.getNamespace().equals(HostNamespace.HOST_NAMESPACE))
{
Capability origCap = ((HostedCapability) c).getDeclaredCapability();
// Note that you might think we could remove the original cap
// from the dependent map, but you can't since it may come from
// a fragment that is attached to multiple hosts, so each host
// will need to make their own copy.
Set<Requirement> dependents = m_dependentMap.get(origCap);
if (dependents != null)
{
dependents = new HashSet<Requirement>(dependents);
m_dependentMap.put(c, dependents);
for (Requirement r : dependents)
{
// We have synthesized hosted capabilities for all
// fragments that have been attached to hosts by
// wrapping the host bundle and their attached
// fragments. We need to use the ResolveContext to
// determine the proper priority order for hosted
// capabilities since the order may depend on the
// declaring host/fragment combination. However,
// internally we completely wrap the host revision
// and make all capabilities/requirements point back
// to the wrapped host not the declaring host. The
// ResolveContext expects HostedCapabilities to point
// to the declaring revision, so we need two separate
// candidate lists: one for the ResolveContext with
// HostedCapabilities pointing back to the declaring
// host and one for the resolver with HostedCapabilities
// pointing back to the wrapped host. We ask the
// ResolveContext to insert its appropriate HostedCapability
// into its list, then we mirror the insert into a
// shadow list with the resolver's HostedCapability.
// We only need to ask the ResolveContext to find
// the insert position for fragment caps since these
// were synthesized and we don't know their priority.
// However, in the resolver's candidate list we need
// to replace all caps with the wrapped caps, no
// matter if they come from the host or fragment,
// since we are completing replacing the declaring
// host and fragments with the wrapped host.
List<Capability> cands = m_candidateMap.get(r);
if (!(cands instanceof ShadowList))
{
ShadowList<Capability> shadow =
new ShadowList<Capability>(cands);
m_candidateMap.put(r, shadow);
cands = shadow;
}
// If the original capability is from a fragment, then
// ask the ResolveContext to insert it and update the
// shadow copy of the list accordingly.
if (!origCap.getResource().equals(hostResource.getDeclaredResource()))
{
List<Capability> original = ((ShadowList) cands).getOriginal();
int removeIdx = original.indexOf(origCap);
if (removeIdx != -1)
{