List<BundleRevision> unselectedFragments = new ArrayList<BundleRevision>();
for (Entry<BundleCapability, Map<String, Map<Version, List<BundleRequirement>>>>
hostEntry : hostFragments.entrySet())
{
// Step 1
BundleCapability hostCap = hostEntry.getKey();
Map<String, Map<Version, List<BundleRequirement>>> fragments
= hostEntry.getValue();
List<BundleRevision> selectedFragments = new ArrayList<BundleRevision>();
for (Entry<String, Map<Version, List<BundleRequirement>>> fragEntry
: fragments.entrySet())
{
boolean isFirst = true;
for (Entry<Version, List<BundleRequirement>> versionEntry
: fragEntry.getValue().entrySet())
{
for (BundleRequirement 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.getRevision());
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<BundleCapability> hosts = m_candidateMap.get(hostReq);
hosts.remove(hostCap);
if (hosts.isEmpty())
{
unselectedFragments.add(hostReq.getRevision());
}
}
}
}
}
// Step 2
WrappedRevision wrappedHost =
new WrappedRevision(hostCap.getRevision(), selectedFragments);
hostRevisions.add(wrappedHost);
m_allWrappedHosts.put(hostCap.getRevision(), wrappedHost);
}
// Step 3
for (BundleRevision br : unselectedFragments)
{
removeRevision(br,
new ResolveException(
"Fragment was not selected for attachment.", br, null));
}
// Step 4
for (WrappedRevision hostRevision : hostRevisions)
{
// Replaces capabilities from fragments with the capabilities
// from the merged host.
for (BundleCapability c : hostRevision.getDeclaredCapabilities(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(BundleRevision.HOST_NAMESPACE))
{
BundleCapability 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<BundleRequirement> dependents = m_dependentMap.get(origCap);
if (dependents != null)
{
dependents = new HashSet<BundleRequirement>(dependents);
m_dependentMap.put(c, dependents);
for (BundleRequirement 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<BundleCapability> cands = m_candidateMap.get(r);
if (!(cands instanceof ShadowList))
{
ShadowList<BundleCapability> shadow =
new ShadowList<BundleCapability>(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.getRevision().equals(hostRevision.getHost()))
{
List<BundleCapability> original = ((ShadowList) cands).getOriginal();
int removeIdx = original.indexOf(origCap);
original.remove(removeIdx);
int insertIdx = rc.insertHostedCapability(