in framework/src/main/java/org/apache/felix/framework/StatefulResolver.java [1020:1243]
private void markResolvedRevisions(Map<Resource, List<Wire>> wireMap)
throws ResolveException
{
boolean debugLog = m_felix.getLogger().getLogLevel() >= Logger.LOG_DEBUG;
// DO THIS IN THREE PASSES:
// 1. Aggregate fragments per host.
// 2. Attach wires and fragments to hosts.
// -> If fragments fail to attach, then undo.
// 3. Mark hosts and fragments as resolved.
// First pass.
if (wireMap != null)
{
// First pass: Loop through the wire map to find the host wires
// for any fragments and map a host to all of its fragments.
Map<Resource, List<BundleRevision>> hosts =
new HashMap<>();
for (Entry<Resource, List<Wire>> entry : wireMap.entrySet())
{
Resource revision = entry.getKey();
List<Wire> wires = entry.getValue();
if (Util.isFragment(revision))
{
for (Wire w : wires)
{
List<BundleRevision> fragments = hosts.get(w.getProvider());
if (fragments == null)
{
fragments = new ArrayList<>();
hosts.put(w.getProvider(), fragments);
}
if (w.getRequirer() instanceof BundleRevision)
fragments.add((BundleRevision) w.getRequirer());
}
}
}
// Second pass: Loop through the wire map to do three things:
// 1) convert resolver wires to bundle wires 2) create wiring
// objects for revisions and 3) record dependencies among
// revisions. We don't actually set the wirings here because
// that indicates that a revision is resolved and we don't want
// to mark anything as resolved unless we succussfully create
// all wirings.
Map<BundleRevision, BundleWiringImpl> wirings =
new HashMap<>(wireMap.size());
for (Entry<Resource, List<Wire>> entry : wireMap.entrySet())
{
Resource resource = entry.getKey();
if (!(resource instanceof BundleRevision))
continue;
BundleRevision revision = (BundleRevision) resource;
List<Wire> resolverWires = entry.getValue();
List<BundleWire> bundleWires =
new ArrayList<>(resolverWires.size());
// Need to special case fragments since they may already have
// wires if they are already attached to another host; if that
// is the case, then we want to merge the old host wires with
// the new ones.
if ((revision.getWiring() != null) && Util.isFragment(revision))
{
// Fragments only have host wires, so just add them all.
bundleWires.addAll(revision.getWiring().getRequiredWires(null));
}
// Loop through resolver wires to calculate the package
// space implied by the wires as well as to record the
// dependencies.
Map<String, BundleRevision> importedPkgs =
new HashMap<>();
Map<String, List<BundleRevision>> requiredPkgs =
new HashMap<>();
for (Wire rw : resolverWires)
{
// TODO is a rw already a BundleWire?
// TODO can we optimize this?
if (!(rw.getRequirer() instanceof BundleRevision))
continue;
BundleRevision requirer = (BundleRevision) rw.getRequirer();
if (!(rw.getRequirement() instanceof BundleRequirement))
continue;
BundleRequirement requirement = (BundleRequirement) rw.getRequirement();
if (!(rw.getProvider() instanceof BundleRevision))
continue;
BundleRevision provider = (BundleRevision) rw.getProvider();
if (!(rw.getCapability() instanceof BundleCapability))
continue;
BundleCapability capability = (BundleCapability) rw.getCapability();
BundleWire bw = new BundleWireImpl(
requirer,
requirement,
provider,
capability);
bundleWires.add(bw);
if (Util.isFragment(revision))
{
if (debugLog)
{
m_felix.getLogger().log(
Logger.LOG_DEBUG,
"FRAGMENT WIRE: " + rw.toString());
}
}
else
{
if (debugLog)
{
m_felix.getLogger().log(Logger.LOG_DEBUG, "WIRE: " + rw.toString());
}
if (capability.getNamespace()
.equals(BundleRevision.PACKAGE_NAMESPACE))
{
importedPkgs.put(
(String) capability.getAttributes()
.get(BundleRevision.PACKAGE_NAMESPACE),
provider);
}
else if (capability.getNamespace()
.equals(BundleRevision.BUNDLE_NAMESPACE))
{
Set<String> pkgs = calculateExportedAndReexportedPackages(
provider,
wireMap,
new HashSet<>(),
new HashSet<>());
for (String pkg : pkgs)
{
List<BundleRevision> revs = requiredPkgs.get(pkg);
if (revs == null)
{
revs = new ArrayList<>();
requiredPkgs.put(pkg, revs);
}
revs.add(provider);
}
}
}
}
List<BundleRevision> fragments = hosts.get(revision);
try
{
wirings.put(
revision,
new BundleWiringImpl(
m_felix.getLogger(),
m_felix.getConfig(),
this,
(BundleRevisionImpl) revision,
fragments,
bundleWires,
importedPkgs,
requiredPkgs));
}
catch (Exception ex)
{
// This is a fatal error, so undo everything and
// throw an exception.
for (Entry<BundleRevision, BundleWiringImpl> wiringEntry
: wirings.entrySet())
{
// Dispose of wiring.
try
{
wiringEntry.getValue().dispose();
}
catch (Exception ex2)
{
// We are in big trouble.
RuntimeException rte = new RuntimeException(
"Unable to clean up resolver failure.", ex2);
m_felix.getLogger().log(
Logger.LOG_ERROR,
rte.getMessage(), ex2);
throw rte;
}
}
ResolveException re = new ResolveException(
"Unable to resolve " + revision,
revision, null);
re.initCause(ex);
m_felix.getLogger().log(
Logger.LOG_ERROR,
re.getMessage(), ex);
throw re;
}
}
// Third pass: Loop through the wire map to mark revision as resolved
// and update the resolver state.
for (Entry<BundleRevision, BundleWiringImpl> entry : wirings.entrySet())
{
BundleRevisionImpl revision = (BundleRevisionImpl) entry.getKey();
// Mark revision as resolved.
BundleWiring wiring = entry.getValue();
revision.resolve(entry.getValue());
// Record dependencies.
for (BundleWire bw : wiring.getRequiredWires(null))
{
m_felix.getDependencies().addDependent(bw);
}
// Reindex the revision's capabilities since its resolved
// capabilities could be different than its declared ones
// (e.g., due to substitutable exports).
addRevision(revision);
// Update the state of the revision's bundle to resolved as well.
markBundleResolved(revision);
}
}
}