Modified require-bundle dependency resolution/wiring to obey ordering
implied by the ordering of dependencies in the manifest. More comments
and attempts to improve the code's readability. (FELIX-28)
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@515263 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
index da82e02..0737651 100755
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
@@ -922,11 +922,11 @@
{
List candidatesList = null;
- // The module map maps a module to a map of resolved
- // packages that are accessible by the given module.
- // The set of resolved packages is calculated from the
- // current candidates of the candidates map and the
- // module's metadata.
+ // The reusable module map maps a module to a map of
+ // resolved packages that are accessible by the given
+ // module. The set of resolved packages is calculated
+ // from the current candidates of the candidates map
+ // and the module's metadata.
Map moduleMap = new HashMap();
// Reusable map used to test for cycles.
@@ -962,25 +962,25 @@
}
private boolean isClassSpaceConsistent(
- IModule rootModule, Map moduleMap, Map cycleMap, Map candidatesMap)
+ IModule targetModule, Map moduleMap, Map cycleMap, Map candidatesMap)
{
-//System.out.println("isClassSpaceConsistent("+rootModule+")");
+//System.out.println("isClassSpaceConsistent("+targetModule+")");
// If we are in a cycle, then assume true for now.
- if (cycleMap.get(rootModule) != null)
+ if (cycleMap.get(targetModule) != null)
{
return true;
}
- // Record the root module in the cycle map.
- cycleMap.put(rootModule, rootModule);
+ // Record the target module in the cycle map.
+ cycleMap.put(targetModule, targetModule);
- // Get the package map for the root module, which is a
+ // Get the package map for the target module, which is a
// map of all packages accessible to the module and their
// associated package sources.
- Map pkgMap = getModulePackages(moduleMap, rootModule, candidatesMap);
+ Map pkgMap = getModulePackages(moduleMap, targetModule, candidatesMap);
- // Loop through all of the module's accessible packages and verify
- // that all package sources are consistent.
+ // Loop through all of the target module's accessible packages and
+ // verify that all package sources are consistent.
for (Iterator iter = pkgMap.entrySet().iterator(); iter.hasNext(); )
{
Map.Entry entry = (Map.Entry) iter.next();
@@ -988,9 +988,9 @@
// package sources for the given package.
ResolvedPackage rp = (ResolvedPackage) entry.getValue();
// Loop through each package source and test if it is consistent.
- for (Iterator srcIter = rp.m_sourceSet.iterator(); srcIter.hasNext(); )
+ for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
{
- PackageSource ps = (PackageSource) srcIter.next();
+ PackageSource ps = (PackageSource) rp.m_sourceList.get(srcIdx);
if (!isClassSpaceConsistent(ps.m_module, moduleMap, cycleMap, candidatesMap))
{
return false;
@@ -999,20 +999,20 @@
}
// Now we need to calculate the "uses" constraints of every package
- // accessible to the module based on the current candidates.
- Map usesMap = calculateUsesConstraints(rootModule, moduleMap, candidatesMap);
+ // accessible to the target module based on the current candidates.
+ Map usesMap = calculateUsesConstraints(targetModule, moduleMap, candidatesMap);
// Verify that none of the implied "uses" constraints in the uses map
- // conflict with anything in the root module's package map.
+ // conflict with anything in the target module's package map.
for (Iterator iter = usesMap.entrySet().iterator(); iter.hasNext(); )
{
Map.Entry entry = (Map.Entry) iter.next();
// For the given "used" package, get that package from the
- // root module's package map, if present.
+ // target module's package map, if present.
ResolvedPackage rp = (ResolvedPackage) pkgMap.get(entry.getKey());
- // If the "used" package is also visible to the root module,
+ // If the "used" package is also visible to the target module,
// make sure there is no conflicts in the implied "uses"
// constraints.
if (rp != null)
@@ -1031,21 +1031,24 @@
// package.
ResolvedPackage rpUses = (ResolvedPackage) constraintList.get(constIdx);
// Determine if the implied "uses" constraint is compatible with
- // the root module's package sources for the given "used" package.
- // They are compatible if one is the subset of the other.
- if (rp.isSubset(rpUses) || rpUses.isSubset(rp))
+ // the target module's package sources for the given "used"
+ // package. They are compatible if one is the subset of the other.
+ // Retain the union of the two sets if they are compatible.
+ if (rpUses.isSubset(rp))
{
- // In case they are compatible, then create the union of
- // the root module's package sources and those of the
- // "uses" constraint for continued testing of the
- // remaining "uses" constraints.
- rp.m_sourceSet.addAll(rpUses.m_sourceSet);
+ // Do nothing because we already have the superset.
+ }
+ else if (rp.isSubset(rpUses))
+ {
+ // Keep the superset, i.e., the union.
+ rp.m_sourceList.clear();
+ rp.m_sourceList.addAll(rpUses.m_sourceList);
}
else
{
m_logger.log(
Logger.LOG_DEBUG,
- "Constraint violation for " + rootModule
+ "Constraint violation for " + targetModule
+ " detected; module can see "
+ rp + " and " + rpUses);
return false;
@@ -1057,9 +1060,10 @@
return true;
}
- private Map calculateUsesConstraints(IModule rootModule, Map moduleMap, Map candidatesMap)
+ private Map calculateUsesConstraints(
+ IModule targetModule, Map moduleMap, Map candidatesMap)
{
-//System.out.println("calculateUsesConstraints("+rootModule+")");
+//System.out.println("calculateUsesConstraints("+targetModule+")");
// Map to store calculated uses constraints. This maps a
// package name to a list of resolved packages, where each
// resolved package represents a constraint on anyone
@@ -1070,51 +1074,53 @@
// Re-usable map to detect cycles.
Map cycleMap = new HashMap();
- // Get all packages accessible by the root module.
- Map pkgMap = getModulePackages(moduleMap, rootModule, candidatesMap);
+ // Get all packages accessible by the target module.
+ Map pkgMap = getModulePackages(moduleMap, targetModule, candidatesMap);
- // Each package accessible from the root module is potentially
+ // Each package accessible from the target module is potentially
// comprised of one or more modules, called package sources. The
// "uses" constraints implied by all package sources must be
// calculated and combined to determine the complete set of implied
- // "uses" constraints for each package accessible by the root module.
+ // "uses" constraints for each package accessible by the target module.
for (Iterator iter = pkgMap.entrySet().iterator(); iter.hasNext(); )
{
Map.Entry entry = (Map.Entry) iter.next();
ResolvedPackage rp = (ResolvedPackage) entry.getValue();
- for (Iterator srcIter = rp.m_sourceSet.iterator(); srcIter.hasNext(); )
+ for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
{
usesMap = calculateUsesConstraints(
- (PackageSource) srcIter.next(),
+ (PackageSource) rp.m_sourceList.get(srcIdx),
moduleMap, usesMap, cycleMap, candidatesMap);
}
}
return usesMap;
}
- private Map calculateUsesConstraints(PackageSource ps, Map moduleMap, Map usesMap, Map cycleMap, Map candidatesMap)
+ private Map calculateUsesConstraints(
+ PackageSource psTarget, Map moduleMap, Map usesMap,
+ Map cycleMap, Map candidatesMap)
{
-//System.out.println("calculateUsesConstraints2("+ps.m_module+")");
+//System.out.println("calculateUsesConstraints2("+psTarget.m_module+")");
// If we are in a cycle, then return for now.
- if (cycleMap.get(ps) != null)
+ if (cycleMap.get(psTarget) != null)
{
return usesMap;
}
- // Record the package source in the cycle map.
- cycleMap.put(ps, ps);
+ // Record the target package source in the cycle map.
+ cycleMap.put(psTarget, psTarget);
// Get all packages accessible from the module of the
- // current package source.
- Map pkgMap = getModulePackages(moduleMap, ps.m_module, candidatesMap);
+ // target package source.
+ Map pkgMap = getModulePackages(moduleMap, psTarget.m_module, candidatesMap);
- // Get capability (i.e., package) of the package source.
- Capability cap = (Capability) ps.m_capability;
+ // Get capability (i.e., package) of the target package source.
+ Capability cap = (Capability) psTarget.m_capability;
// Loop through all "used" packages of the capability.
for (int i = 0; i < cap.getUses().length; i++)
{
- // The package source module should have a resolved package
+ // The target package source module should have a resolved package
// for the "used" package in its set of accessible packages,
// since it claims to use it, so get the associated resolved
// package.
@@ -1127,10 +1133,10 @@
// First, iterate through all package sources for the resolved
// package associated with the current "used" package and calculate
// and combine the "uses" constraints for each package source.
- for (Iterator srcIter = rp.m_sourceSet.iterator(); srcIter.hasNext(); )
+ for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
{
usesMap = calculateUsesConstraints(
- (PackageSource) srcIter.next(),
+ (PackageSource) rp.m_sourceList.get(srcIdx),
moduleMap, usesMap, cycleMap, candidatesMap);
}
@@ -1167,6 +1173,20 @@
return map;
}
+ /**
+ * <p>
+ * Calculates the module's set of accessible packages and their
+ * assocaited package sources. This method uses the current candidates
+ * for resolving the module's requirements from the candidate map
+ * to calculate the module's accessible packages.
+ * </p>
+ * @param module the module whose package map is to be calculated.
+ * @param candidatesMap the map of potential candidates for resolving
+ * the module's requirements.
+ * @return a map of the packages accessible to the specified module where
+ * the key of the map is the package name and the value of the map
+ * is a ResolvedPackage.
+ **/
private Map calculateModulePackages(IModule module, Map candidatesMap)
{
//System.out.println("calculateModulePackages("+module+")");
@@ -1183,8 +1203,10 @@
ResolvedPackage rpReq = (ResolvedPackage) requiredPackages.get(entry.getKey());
if (rpReq != null)
{
+ // Merge exported and required packages, avoiding duplicate
+ // package sources and maintaining ordering.
ResolvedPackage rpExport = (ResolvedPackage) entry.getValue();
- rpReq.m_sourceSet.addAll(rpExport.m_sourceSet);
+ rpReq.merge(rpExport);
}
else
{
@@ -1203,25 +1225,25 @@
return requiredPackages;
}
- private Map calculateImportedPackages(IModule module, Map candidatesMap)
+ private Map calculateImportedPackages(IModule targetModule, Map candidatesMap)
{
- return (candidatesMap.get(module) == null)
- ? calculateImportedPackagesResolved(module)
- : calculateImportedPackagesUnresolved(module, candidatesMap);
+ return (candidatesMap.get(targetModule) == null)
+ ? calculateImportedPackagesResolved(targetModule)
+ : calculateImportedPackagesUnresolved(targetModule, candidatesMap);
}
- private Map calculateImportedPackagesUnresolved(IModule module, Map candidatesMap)
+ private Map calculateImportedPackagesUnresolved(IModule targetModule, Map candidatesMap)
{
-//System.out.println("calculateImportedPackagesUnresolved("+module+")");
+//System.out.println("calculateImportedPackagesUnresolved("+targetModule+")");
Map pkgMap = new HashMap();
// Get the candidate set list to get all candidates for
- // all of the module's requirements.
- List candSetList = (List) candidatesMap.get(module);
+ // all of the target module's requirements.
+ List candSetList = (List) candidatesMap.get(targetModule);
// Loop through all candidate sets that represent import dependencies
- // for the module and add the current candidate's package source to the
- // imported package map.
+ // for the target module and add the current candidate's package source
+ // to the imported package map.
for (int candSetIdx = 0; (candSetList != null) && (candSetIdx < candSetList.size()); candSetIdx++)
{
CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
@@ -1233,7 +1255,7 @@
ps.m_capability.getProperties().get(ICapability.PACKAGE_PROPERTY);
ResolvedPackage rp = new ResolvedPackage(pkgName);
- rp.m_sourceSet.add(ps);
+ rp.m_sourceList.add(ps);
pkgMap.put(rp.m_name, rp);
}
}
@@ -1241,15 +1263,15 @@
return pkgMap;
}
- private Map calculateImportedPackagesResolved(IModule module)
+ private Map calculateImportedPackagesResolved(IModule targetModule)
{
-//System.out.println("calculateImportedPackagesResolved("+module+")");
+//System.out.println("calculateImportedPackagesResolved("+targetModule+")");
Map pkgMap = new HashMap();
- // Loop through all wires for the module that represent package
+ // Loop through the target module's wires for package
// dependencies and add the resolved package source to the
// imported package map.
- IWire[] wires = module.getWires();
+ IWire[] wires = targetModule.getWires();
for (int i = 0; (wires != null) && (i < wires.length); i++)
{
if (wires[i].getCapability().getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
@@ -1258,7 +1280,7 @@
wires[i].getCapability().getProperties().get(ICapability.PACKAGE_PROPERTY);
ResolvedPackage rp = (ResolvedPackage) pkgMap.get(pkgName);
rp = (rp == null) ? new ResolvedPackage(pkgName) : rp;
- rp.m_sourceSet.add(new PackageSource(wires[i].getExporter(), wires[i].getCapability()));
+ rp.m_sourceList.add(new PackageSource(wires[i].getExporter(), wires[i].getCapability()));
pkgMap.put(rp.m_name, rp);
}
}
@@ -1266,14 +1288,14 @@
return pkgMap;
}
- private Map calculateExportedPackages(IModule module)
+ private Map calculateExportedPackages(IModule targetModule)
{
-//System.out.println("calculateExportedPackages("+module+")");
+//System.out.println("calculateExportedPackages("+targetModule+")");
Map pkgMap = new HashMap();
- // Loop through all capabilities that represent exported packages
- // and add them to the exported package map.
- ICapability[] caps = module.getDefinition().getCapabilities();
+ // Loop through the target module's capabilities that represent
+ // exported packages and add them to the exported package map.
+ ICapability[] caps = targetModule.getDefinition().getCapabilities();
for (int capIdx = 0; (caps != null) && (capIdx < caps.length); capIdx++)
{
if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
@@ -1282,7 +1304,7 @@
caps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY);
ResolvedPackage rp = (ResolvedPackage) pkgMap.get(pkgName);
rp = (rp == null) ? new ResolvedPackage(pkgName) : rp;
- rp.m_sourceSet.add(new PackageSource(module, caps[capIdx]));
+ rp.m_sourceList.add(new PackageSource(targetModule, caps[capIdx]));
pkgMap.put(rp.m_name, rp);
}
}
@@ -1290,21 +1312,21 @@
return pkgMap;
}
- private Map calculateRequiredPackages(IModule module, Map candidatesMap)
+ private Map calculateRequiredPackages(IModule targetModule, Map candidatesMap)
{
- return (candidatesMap.get(module) == null)
- ? calculateRequiredPackagesResolved(module)
- : calculateRequiredPackagesUnresolved(module, candidatesMap);
+ return (candidatesMap.get(targetModule) == null)
+ ? calculateRequiredPackagesResolved(targetModule)
+ : calculateRequiredPackagesUnresolved(targetModule, candidatesMap);
}
- private Map calculateRequiredPackagesUnresolved(IModule module, Map candidatesMap)
+ private Map calculateRequiredPackagesUnresolved(IModule targetModule, Map candidatesMap)
{
-//System.out.println("calculateRequiredPackagesUnresolved("+module+")");
+//System.out.println("calculateRequiredPackagesUnresolved("+targetModule+")");
Map pkgMap = new HashMap();
- // Loop through all current candidates for module dependencies and
- // merge re-exported packages.
- List candSetList = (List) candidatesMap.get(module);
+ // Loop through target module's candidate list for candidates
+ // for its module dependencies and merge re-exported packages.
+ List candSetList = (List) candidatesMap.get(targetModule);
for (int candSetIdx = 0; (candSetList != null) && (candSetIdx < candSetList.size()); candSetIdx++)
{
CandidateSet cs = (CandidateSet) candSetList.get(candSetIdx);
@@ -1315,20 +1337,24 @@
{
// Calculate transitively required packages.
Map cycleMap = new HashMap();
- cycleMap.put(module, module);
- Map requireMap = calculateExportedAndReexportedPackages(
- ps, candidatesMap, new HashMap(), cycleMap);
+ cycleMap.put(targetModule, targetModule);
+ Map requireMap =
+ calculateExportedAndReexportedPackages(
+ ps, candidatesMap, cycleMap);
- // Loop through all export package capabilities and merge them
- // into the package map adding the original target as a source.
+ // Take the flattened required package map for the current
+ // module dependency and merge it into the existing map
+ // of required packages.
for (Iterator reqIter = requireMap.entrySet().iterator(); reqIter.hasNext(); )
{
Map.Entry entry = (Map.Entry) reqIter.next();
ResolvedPackage rp = (ResolvedPackage) pkgMap.get(entry.getKey());
if (rp != null)
{
+ // Merge required packages, avoiding duplicate
+ // package sources and maintaining ordering.
ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
- rp.m_sourceSet.addAll(rpReq.m_sourceSet);
+ rp.merge(rpReq);
}
else
{
@@ -1341,34 +1367,42 @@
return pkgMap;
}
- private Map calculateRequiredPackagesResolved(IModule module)
+ private Map calculateRequiredPackagesResolved(IModule targetModule)
{
-//System.out.println("calculateRequiredPackagesResolved("+module+")");
+//System.out.println("calculateRequiredPackagesResolved("+targetModule+")");
Map pkgMap = new HashMap();
- IWire[] wires = module.getWires();
+ // Loop through target module's wires for module dependencies
+ // and merge re-exported packages.
+ IWire[] wires = targetModule.getWires();
for (int i = 0; (wires != null) && (i < wires.length); i++)
{
- // If the candidate is a module dependency, then flatten it to packages.
+ // If the wire is a module dependency, then flatten it to packages.
if (wires[i].getCapability().getNamespace().equals(ICapability.MODULE_NAMESPACE))
{
+ // Calculate transitively required packages.
// We can call calculateExportedAndReexportedPackagesResolved()
// directly, since we know all dependencies have to be resolved
// because this module itself is resolved.
Map cycleMap = new HashMap();
- cycleMap.put(module, module);
- Map requireMap = calculateExportedAndReexportedPackagesResolved(
- wires[i].getExporter(), new HashMap(), cycleMap);
+ cycleMap.put(targetModule, targetModule);
+ Map requireMap =
+ calculateExportedAndReexportedPackagesResolved(
+ wires[i].getExporter(), cycleMap);
- // Merge sources.
+ // Take the flattened required package map for the current
+ // module dependency and merge it into the existing map
+ // of required packages.
for (Iterator reqIter = requireMap.entrySet().iterator(); reqIter.hasNext(); )
{
Map.Entry entry = (Map.Entry) reqIter.next();
ResolvedPackage rp = (ResolvedPackage) pkgMap.get(entry.getKey());
if (rp != null)
{
+ // Merge required packages, avoiding duplicate
+ // package sources and maintaining ordering.
ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
- rp.m_sourceSet.addAll(rpReq.m_sourceSet);
+ rp.merge(rpReq);
}
else
{
@@ -1381,16 +1415,20 @@
return pkgMap;
}
- private Map calculateExportedAndReexportedPackages(PackageSource psTarget, Map candidatesMap, Map pkgMap, Map cycleMap)
+ private Map calculateExportedAndReexportedPackages(
+ PackageSource psTarget, Map candidatesMap, Map cycleMap)
{
return (candidatesMap.get(psTarget.m_module) == null)
- ? calculateExportedAndReexportedPackagesResolved(psTarget.m_module, pkgMap, cycleMap)
- : calculateExportedAndReexportedPackagesUnresolved(psTarget, candidatesMap, pkgMap, cycleMap);
+ ? calculateExportedAndReexportedPackagesResolved(psTarget.m_module, cycleMap)
+ : calculateExportedAndReexportedPackagesUnresolved(psTarget, candidatesMap, cycleMap);
}
- private Map calculateExportedAndReexportedPackagesUnresolved(PackageSource psTarget, Map candidatesMap, Map pkgMap, Map cycleMap)
+ private Map calculateExportedAndReexportedPackagesUnresolved(
+ PackageSource psTarget, Map candidatesMap, Map cycleMap)
{
//System.out.println("calculateExportedAndReexportedPackagesUnresolved("+psTarget.m_module+")");
+ Map pkgMap = new HashMap();
+
if (cycleMap.get(psTarget.m_module) != null)
{
return pkgMap;
@@ -1398,25 +1436,12 @@
cycleMap.put(psTarget.m_module, psTarget.m_module);
- // Loop through all export package capabilities and merge them
- // into the package map adding the original target as a source.
- ICapability[] candCaps = psTarget.m_module.getDefinition().getCapabilities();
- for (int capIdx = 0; (candCaps != null) && (capIdx < candCaps.length); capIdx++)
- {
- if (candCaps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
- {
- String pkgName = (String)
- candCaps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY);
- ResolvedPackage rp = (ResolvedPackage) pkgMap.get(pkgName);
- rp = (rp == null) ? new ResolvedPackage(pkgName) : rp;
- rp.m_sourceSet.add(new PackageSource(psTarget.m_module, candCaps[capIdx]));
- pkgMap.put(rp.m_name, rp);
- }
- }
-
- // Loop through all current candidates for module dependencies and
- // merge re-exported packages.
+ // Loop through all current candidates for target module's dependencies
+ // and calculate the module's complete set of required packages (and
+ // their associated package sources) and the complete set of required
+ // packages to be re-exported.
Map allRequiredMap = new HashMap();
+ Map reexportedPkgMap = new HashMap();
List candSetList = (List) candidatesMap.get(psTarget.m_module);
for (int candSetIdx = 0; candSetIdx < candSetList.size(); candSetIdx++)
{
@@ -1442,9 +1467,10 @@
// Recursively calculate the required packages for the
// current candidate.
- Map requiredMap = calculateExportedAndReexportedPackages(ps, candidatesMap, new HashMap(), cycleMap);
+ Map requiredMap = calculateExportedAndReexportedPackages(ps, candidatesMap, cycleMap);
- // Merge the candidate's required packages with the existing packages.
+ // Merge the candidate's exported and re-exported packages
+ // into the complete set of required packages.
for (Iterator reqIter = requiredMap.entrySet().iterator(); reqIter.hasNext(); )
{
Map.Entry entry = (Map.Entry) reqIter.next();
@@ -1452,86 +1478,91 @@
// Merge the current set of required packages into
// the overall complete set of required packages.
- // We must keep track of all possible re-exported
- // packages, because despite the fact that some packages
- // will be required "privately" and some will be required
- // "reexport", any re-exported package sources will
- // ultimately need to be combined with privately required
- // package sources, if the required packages overlap.
- // This is one of the bad things about require-bundle
- // behavior, it does not necessarily obey the visibility
- // rules declared in the dependency.
+ // We calculate all the required packages, because
+ // despite the fact that some packages will be required
+ // "privately" and some will be required "reexport", any
+ // re-exported package sources will ultimately need to
+ // be combined with privately required package sources,
+ // if the required packages overlap. This is one of the
+ // bad things about require-bundle behavior, it does not
+ // necessarily obey the visibility rules declared in the
+ // dependency.
ResolvedPackage rp = (ResolvedPackage) allRequiredMap.get(pkgName);
if (rp != null)
{
// Create the union of all package sources.
ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
- rp.m_sourceSet.addAll(rpReq.m_sourceSet);
+ rp.merge(rpReq);
}
else
{
- allRequiredMap.put(entry.getKey(), entry.getValue());
+ // Add package to required map.
+ allRequiredMap.put(pkgName, entry.getValue());
}
- // Now merge any re-exported packages into the module's
- // overall package map, since these re-exported packages
- // will become part of the module's export signature.
- rp = (ResolvedPackage) pkgMap.get(entry.getKey());
- if ((rp == null) && reexport)
+ // Keep track of all required packages to be re-exported.
+ // All re-exported packages will need to be merged into the
+ // target module's package map and become part of its overall
+ // export signature.
+ if (reexport)
{
- pkgMap.put(entry.getKey(), entry.getValue());
+ reexportedPkgMap.put(pkgName, pkgName);
}
}
}
}
- // Using the package map that represents the module's complete
- // export signature (i.e., it includes exported and re-exported
- // packages), merge in the package sources for any required
- // packages that overlap the set of exported/re-exported packages.
- for (Iterator reqIter = allRequiredMap.entrySet().iterator(); reqIter.hasNext(); )
+ // For the target module we have now calculated its entire set
+ // of required packages and their associated package sources in
+ // allRequiredMap and have calculated all packages to be re-exported
+ // in reexportedPkgMap. Add all re-exported required packages to the
+ // target module's package map since they will be part of its export
+ // signature.
+ for (Iterator iter = reexportedPkgMap.entrySet().iterator(); iter.hasNext(); )
{
- Map.Entry entry = (Map.Entry) reqIter.next();
- ResolvedPackage rp = (ResolvedPackage) pkgMap.get(entry.getKey());
- if (rp != null)
+ String pkgName = (String) ((Map.Entry) iter.next()).getKey();
+ pkgMap.put(pkgName, allRequiredMap.get(pkgName));
+ }
+
+ // Now loop through the target module's export package capabilities and
+ // add the target module as a package source for any exported packages.
+ ICapability[] candCaps = psTarget.m_module.getDefinition().getCapabilities();
+ for (int capIdx = 0; (candCaps != null) && (capIdx < candCaps.length); capIdx++)
+ {
+ if (candCaps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
{
- // Create the union of all package sources.
- ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
- rp.m_sourceSet.addAll(rpReq.m_sourceSet);
+ String pkgName = (String)
+ candCaps[capIdx].getProperties().get(ICapability.PACKAGE_PROPERTY);
+ ResolvedPackage rp = (ResolvedPackage) pkgMap.get(pkgName);
+ rp = (rp == null) ? new ResolvedPackage(pkgName) : rp;
+ rp.m_sourceList.add(new PackageSource(psTarget.m_module, candCaps[capIdx]));
+ pkgMap.put(rp.m_name, rp);
}
}
return pkgMap;
}
- private Map calculateExportedAndReexportedPackagesResolved(IModule module, Map pkgMap, Map cycleMap)
+ private Map calculateExportedAndReexportedPackagesResolved(
+ IModule targetModule, Map cycleMap)
{
-//System.out.println("calculateExportedAndRequiredPackagesResolved("+module+")");
- if (cycleMap.get(module) != null)
+//System.out.println("calculateExportedAndRequiredPackagesResolved("+targetModule+")");
+ Map pkgMap = new HashMap();
+
+ if (cycleMap.get(targetModule) != null)
{
return pkgMap;
}
- cycleMap.put(module, module);
+ cycleMap.put(targetModule, targetModule);
- // Loop through all export package capabilities and merge them
- // into the package map adding the original target as a source.
- ICapability[] caps = module.getDefinition().getCapabilities();
- for (int i = 0; (caps != null) && (i < caps.length); i++)
- {
- if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
- {
- String pkgName = (String)
- caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY);
- ResolvedPackage rp = (ResolvedPackage) pkgMap.get(pkgName);
- rp = (rp == null) ? new ResolvedPackage(pkgName) : rp;
- rp.m_sourceSet.add(new PackageSource(module, caps[i]));
- pkgMap.put(rp.m_name, rp);
- }
- }
-
+ // Loop through all wires for the target module's module dependencies
+ // and calculate the module's complete set of required packages (and
+ // their associated package sources) and the complete set of required
+ // packages to be re-exported.
Map allRequiredMap = new HashMap();
- IWire[] wires = module.getWires();
+ Map reexportedPkgMap = new HashMap();
+ IWire[] wires = targetModule.getWires();
for (int i = 0; (wires != null) && (i < wires.length); i++)
{
// If the wire is a module dependency, then flatten it to packages.
@@ -1552,10 +1583,10 @@
// Recursively calculate the required packages for the
// wire's exporting module.
- Map requiredMap = calculateExportedAndReexportedPackagesResolved(wires[i].getExporter(), new HashMap(), cycleMap);
+ Map requiredMap = calculateExportedAndReexportedPackagesResolved(wires[i].getExporter(), cycleMap);
- // Merge the exporting module's required packages with the
- // existing packages.
+ // Merge the wires exported and re-exported packages
+ // into the complete set of required packages.
for (Iterator reqIter = requiredMap.entrySet().iterator(); reqIter.hasNext(); )
{
Map.Entry entry = (Map.Entry) reqIter.next();
@@ -1563,52 +1594,65 @@
// Merge the current set of required packages into
// the overall complete set of required packages.
- // We must keep track of all possible re-exported
- // packages, because despite the fact that some packages
- // will be required "privately" and some will be required
- // "reexport", any re-exported package sources will
- // ultimately need to be combined with privately required
- // package sources, if the required packages overlap.
- // This is one of the bad things about require-bundle
- // behavior, it does not necessarily obey the visibility
- // rules declared in the dependency.
+ // We calculate all the required packages, because
+ // despite the fact that some packages will be required
+ // "privately" and some will be required "reexport", any
+ // re-exported package sources will ultimately need to
+ // be combined with privately required package sources,
+ // if the required packages overlap. This is one of the
+ // bad things about require-bundle behavior, it does not
+ // necessarily obey the visibility rules declared in the
+ // dependency.
ResolvedPackage rp = (ResolvedPackage) allRequiredMap.get(pkgName);
if (rp != null)
{
// Create the union of all package sources.
ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
- rp.m_sourceSet.addAll(rpReq.m_sourceSet);
+ rp.merge(rpReq);
}
else
{
- allRequiredMap.put(entry.getKey(), entry.getValue());
+ // Add package to required map.
+ allRequiredMap.put(pkgName, entry.getValue());
}
- // Now merge any re-exported packages into the module's
- // overall package map, since these re-exported packages
- // will become part of the module's export signature.
- rp = (ResolvedPackage) pkgMap.get(entry.getKey());
- if ((rp == null) && reexport)
+ // Keep track of all required packages to be re-exported.
+ // All re-exported packages will need to be merged into the
+ // target module's package map and become part of its overall
+ // export signature.
+ if (reexport)
{
- pkgMap.put(entry.getKey(), entry.getValue());
+ reexportedPkgMap.put(pkgName, pkgName);
}
}
}
}
- // Using the package map that represents the module's complete
- // export signature (i.e., it includes exported and re-exported
- // packages), merge in the package sources for any required
- // packages that overlap the set of exported/re-exported packages.
- for (Iterator reqIter = allRequiredMap.entrySet().iterator(); reqIter.hasNext(); )
+ // For the target module we have now calculated its entire set
+ // of required packages and their associated package sources in
+ // allRequiredMap and have calculated all packages to be re-exported
+ // in reexportedPkgMap. Add all re-exported required packages to the
+ // target module's package map since they will be part of its export
+ // signature.
+ for (Iterator iter = reexportedPkgMap.entrySet().iterator(); iter.hasNext(); )
{
- Map.Entry entry = (Map.Entry) reqIter.next();
- ResolvedPackage rp = (ResolvedPackage) pkgMap.get(entry.getKey());
- if (rp != null)
+ String pkgName = (String) ((Map.Entry) iter.next()).getKey();
+ pkgMap.put(pkgName, allRequiredMap.get(pkgName));
+ }
+
+ // Now loop through the target module's export package capabilities and
+ // add the target module as a package source for any exported packages.
+ ICapability[] caps = targetModule.getDefinition().getCapabilities();
+ for (int i = 0; (caps != null) && (i < caps.length); i++)
+ {
+ if (caps[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
{
- // Create the union of all package sources.
- ResolvedPackage rpReq = (ResolvedPackage) entry.getValue();
- rp.m_sourceSet.addAll(rpReq.m_sourceSet);
+ String pkgName = (String)
+ caps[i].getProperties().get(ICapability.PACKAGE_PROPERTY);
+ ResolvedPackage rp = (ResolvedPackage) pkgMap.get(pkgName);
+ rp = (rp == null) ? new ResolvedPackage(pkgName) : rp;
+ rp.m_sourceList.add(new PackageSource(targetModule, caps[i]));
+ pkgMap.put(rp.m_name, rp);
}
}
@@ -1620,7 +1664,7 @@
//System.out.println("calculateCandidateRequiredPackages("+module+")");
Map cycleMap = new HashMap();
cycleMap.put(module, module);
- return calculateExportedAndReexportedPackages(psTarget, candidatesMap, new HashMap(), cycleMap);
+ return calculateExportedAndReexportedPackages(psTarget, candidatesMap, cycleMap);
}
private void incrementCandidateConfiguration(List resolverList)
@@ -2357,7 +2401,7 @@
protected class ResolvedPackage
{
public String m_name = null;
- public Set m_sourceSet = new HashSet();
+ public List m_sourceList = new ArrayList();
public ResolvedPackage(String name)
{
@@ -2366,26 +2410,39 @@
public boolean isSubset(ResolvedPackage rp)
{
- if (rp.m_sourceSet.size() > m_sourceSet.size())
+ if (m_sourceList.size() > rp.m_sourceList.size())
{
return false;
}
- else if (!rp.m_name.equals(m_name))
+ else if (!m_name.equals(rp.m_name))
{
return false;
}
// Determine if the target set of source modules is a subset.
- return m_sourceSet.containsAll(rp.m_sourceSet);
+ return rp.m_sourceList.containsAll(m_sourceList);
}
public Object clone()
{
ResolvedPackage rp = new ResolvedPackage(m_name);
- rp.m_sourceSet.addAll(m_sourceSet);
+ rp.m_sourceList.addAll(m_sourceList);
return rp;
}
+ public void merge(ResolvedPackage rp)
+ {
+ // Merge required packages, avoiding duplicate
+ // package sources and maintaining ordering.
+ for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
+ {
+ if (!m_sourceList.contains(rp.m_sourceList.get(srcIdx)))
+ {
+ m_sourceList.add(rp.m_sourceList.get(srcIdx));
+ }
+ }
+ }
+
public String toString()
{
return toString("", new StringBuffer()).toString();
@@ -2396,11 +2453,11 @@
sb.append(padding);
sb.append(m_name);
sb.append(" from [");
- for (Iterator i = m_sourceSet.iterator(); i.hasNext(); )
+ for (int i = 0; i < m_sourceList.size(); i++)
{
- PackageSource ps = (PackageSource) i.next();
+ PackageSource ps = (PackageSource) m_sourceList.get(i);
sb.append(ps.m_module);
- if (i.hasNext())
+ if ((i + 1) < m_sourceList.size())
{
sb.append(", ");
}
@@ -2410,6 +2467,7 @@
}
}
+ // TODO: RB - This may come back once we optimize filter evaluation.
private class InUse
{
public IModule m_module = null;
@@ -2709,4 +2767,4 @@
return sb.toString();
}
-}
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java
index 18d3739..38c165d 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java
@@ -88,9 +88,9 @@
ResolvedPackage rp = (ResolvedPackage) m_pkgMap.get(pkgName);
if (rp != null)
{
- for (Iterator srcIter = rp.m_sourceSet.iterator(); srcIter.hasNext(); )
+ for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
{
- PackageSource ps = (PackageSource) srcIter.next();
+ PackageSource ps = (PackageSource) rp.m_sourceList.get(srcIdx);
if ((ps.m_module == m_importer) ||
((ps.m_capability instanceof Capability) &&
((Capability) ps.m_capability).isIncluded(name)))
@@ -118,9 +118,9 @@
ResolvedPackage rp = (ResolvedPackage) m_pkgMap.get(pkgName);
if (rp != null)
{
- for (Iterator srcIter = rp.m_sourceSet.iterator(); srcIter.hasNext(); )
+ for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
{
- PackageSource ps = (PackageSource) srcIter.next();
+ PackageSource ps = (PackageSource) rp.m_sourceList.get(srcIdx);
URL url = ps.m_module.getContentLoader().getResource(name);
if (url != null)
{