Modified the module implementation to keep track of modules that are
dependent on it (i.e., via import-package and require-bundle wires). This
makes it much more efficient to calculate dependency graphs and fixes
one missing piece of require-bundle functionality where required bundles
were not part of the calculated dependency graph for Package Admin.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@547342 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index bd1e8d2..b02c547 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -1571,15 +1571,12 @@
fireBundleEvent(BundleEvent.UPDATED, bundle);
// Determine if the bundle is in use by anyone.
-// TODO: FRAMEWORK - This is really inefficient since it will end up looping
-// through all bundles and their imports, maybe we should keep track of
-// wiring.
- List usedPackages = new ArrayList();
- getExportedPackages(bundle, usedPackages);
boolean used = false;
- for (int i = 0; !used && (i < usedPackages.size()); i++)
+ IModule[] modules = info.getModules();
+ for (int i = 0; !used && (i < modules.length); i++)
{
- if (((ExportedPackageImpl) usedPackages.get(i)).getImportingBundles() != null)
+ IModule[] dependents = ((ModuleImpl) modules[i]).getDependents();
+ if ((dependents != null) && (dependents.length > 0))
{
used = true;
}
@@ -1836,35 +1833,32 @@
fireBundleEvent(BundleEvent.UNINSTALLED, bundle);
// Determine if the bundle is in use by anyone.
-// TODO: FRAMEWORK - This is really inefficient since it will end up looping
-// through all bundles and their imports, maybe we should keep track of
-// wiring.
- List usedPackages = new ArrayList();
- getExportedPackages(bundle, usedPackages);
- boolean used = false;
- for (int i = 0; !used && (i < usedPackages.size()); i++)
- {
- if (((ExportedPackageImpl) usedPackages.get(i)).getImportingBundles() != null)
- {
- used = true;
- }
- }
+ boolean used = false;
+ IModule[] modules = info.getModules();
+ for (int i = 0; !used && (i < modules.length); i++)
+ {
+ IModule[] dependents = ((ModuleImpl) modules[i]).getDependents();
+ if ((dependents != null) && (dependents.length > 0))
+ {
+ used = true;
+ }
+ }
- // If the bundle is not used by anyone, then garbage
- // collect it now.
- if (!used)
- {
- try
- {
- refreshPackages(new Bundle[] { bundle });
- }
- catch (Exception ex)
- {
- m_logger.log(
- Logger.LOG_ERROR,
- "Unable to immediately garbage collect the bundle.", ex);
- }
- }
+ // If the bundle is not used by anyone, then garbage
+ // collect it now.
+ if (!used)
+ {
+ try
+ {
+ refreshPackages(new Bundle[] { bundle });
+ }
+ catch (Exception ex)
+ {
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Unable to immediately garbage collect the bundle.", ex);
+ }
+ }
}
//
@@ -2855,36 +2849,62 @@
}
}
- protected Bundle[] getImportingBundles(ExportedPackage ep)
+ protected Bundle[] getDependentBundles(BundleImpl exporter)
{
// Get exporting bundle.
- BundleImpl exporter = (BundleImpl)
- ((ExportedPackage) ep).getExportingBundle();
BundleInfo exporterInfo = exporter.getInfo();
// Create list for storing importing bundles.
List list = new ArrayList();
- Bundle[] bundles = getBundles();
- // Check all bundles to see who imports the package.
- for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
+ // Get all dependent modules from all exporter module revisions.
+ IModule[] modules = exporterInfo.getModules();
+ for (int modIdx = 0; modIdx < modules.length; modIdx++)
{
- BundleImpl importer = (BundleImpl) bundles[bundleIdx];
-
- // Check the import wires of all modules for all bundles.
- IModule[] modules = importer.getInfo().getModules();
- for (int modIdx = 0; modIdx < modules.length; modIdx++)
+ IModule[] dependents = ((ModuleImpl) modules[modIdx]).getDependents();
+ for (int depIdx = 0;
+ (dependents != null) && (depIdx < dependents.length);
+ depIdx++)
{
- IWire wire = Util.getWire(modules[modIdx], ep.getName());
+ Bundle b = getBundle(Util.getBundleIdFromModuleId(dependents[depIdx].getId()));
+ list.add(b);
+ }
+ }
- // If the resolving module is associated with the
- // exporting bundle, then add current bundle to
- // import list.
- if ((wire != null) && exporterInfo.hasModule(wire.getExporter()))
+ // Return the results.
+ if (list.size() > 0)
+ {
+ return (Bundle[]) list.toArray(new Bundle[list.size()]);
+ }
+
+ return null;
+ }
+
+ protected Bundle[] getImportingBundles(ExportedPackage ep)
+ {
+ // Create list for storing importing bundles.
+ List list = new ArrayList();
+
+ // Get exporting bundle information.
+ BundleImpl exporter = (BundleImpl)
+ ((ExportedPackage) ep).getExportingBundle();
+
+ // Search the dependents of the exporter's module revisions
+ // for importers of the specific package.
+ IModule[] expModules = exporter.getInfo().getModules();
+ for (int expIdx = 0; (expModules != null) && (expIdx < expModules.length); expIdx++)
+ {
+ IModule[] depModules = ((ModuleImpl) expModules[expIdx]).getDependents();
+ for (int depIdx = 0; (depModules != null) && (depIdx < depModules.length); depIdx++)
+ {
+ // See if the dependent module has a wire for the specific
+ // package. If so, see if the provider module is from the
+ // exporter and record it if it is.
+ IWire wire = Util.getWire(depModules[depIdx], ep.getName());
+ if ((wire != null) && expModules[expIdx].equals(wire.getExporter()))
{
// Add the bundle to the list of importers.
- list.add(bundles[bundleIdx]);
- break;
+ list.add(getBundle(Util.getBundleIdFromModuleId(depModules[depIdx].getId())));
}
}
}
@@ -3031,29 +3051,23 @@
fireFrameworkEvent(FrameworkEvent.PACKAGES_REFRESHED, getBundle(0), null);
}
- private void populateImportGraph(BundleImpl target, Map map)
+ private void populateImportGraph(BundleImpl exporter, Map map)
{
- // Get the exported packages for the specified bundle.
- ExportedPackage[] pkgs = getExportedPackages(target);
+ // Get all dependent bundles of this bundle.
+ Bundle[] importers = getDependentBundles(exporter);
- for (int pkgIdx = 0; (pkgs != null) && (pkgIdx < pkgs.length); pkgIdx++)
+ for (int impIdx = 0;
+ (importers != null) && (impIdx < importers.length);
+ impIdx++)
{
- // Get all imports of this package.
- Bundle[] importers = getImportingBundles(pkgs[pkgIdx]);
-
- for (int impIdx = 0;
- (importers != null) && (impIdx < importers.length);
- impIdx++)
+ // Avoid cycles if the bundle is already in map.
+ if (!map.containsKey(importers[impIdx]))
{
- // Avoid cycles if the bundle is already in map.
- if (!map.containsKey(importers[impIdx]))
- {
- // Add each importing bundle to map.
- map.put(importers[impIdx], importers[impIdx]);
- // Now recurse into each bundle to get its importers.
- populateImportGraph(
- (BundleImpl) importers[impIdx], map);
- }
+ // Add each importing bundle to map.
+ map.put(importers[impIdx], importers[impIdx]);
+ // Now recurse into each bundle to get its importers.
+ populateImportGraph(
+ (BundleImpl) importers[impIdx], map);
}
}
}
diff --git a/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java b/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java
index 9e65e8b..8611ecd 100644
--- a/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java
@@ -178,9 +178,9 @@
* @return an array of packages exported by the bundle or null if the
* bundle does not export any packages.
**/
- public ExportedPackage[] getExportedPackages(Bundle b)
+ public ExportedPackage[] getExportedPackages(Bundle bundle)
{
- return m_felix.getExportedPackages(b);
+ return m_felix.getExportedPackages(bundle);
}
/**
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java
index 70c08e2..9be24f0 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java
@@ -61,8 +61,14 @@
protected Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
+ Class clazz = null;
+
// Make sure the class was not already loaded.
- Class clazz = findLoadedClass(name);
+ synchronized (this)
+ {
+ clazz = findLoadedClass(name);
+ }
+
if (clazz == null)
{
// Ask the search policy for the class.
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 42e4dce..7e98692 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
@@ -2395,6 +2395,9 @@
}
}
+ // Set wires to null, which will remove the module from all
+ // of its dependent modules.
+ ((ModuleImpl) event.getModule()).setWires(null);
// Remove the module from the "in use" map.
// TODO: RB - Maybe this can be merged with ModuleData.
m_inUseCapMap.remove(event.getModule());
diff --git a/framework/src/main/java/org/apache/felix/moduleloader/ModuleImpl.java b/framework/src/main/java/org/apache/felix/moduleloader/ModuleImpl.java
index fd598f8..6f2d84f 100644
--- a/framework/src/main/java/org/apache/felix/moduleloader/ModuleImpl.java
+++ b/framework/src/main/java/org/apache/felix/moduleloader/ModuleImpl.java
@@ -31,6 +31,7 @@
private IModuleDefinition m_md = null;
private IContentLoader m_contentLoader = null;
private IWire[] m_wires = null;
+ private IModule[] m_dependents = new IModule[0];
private Object m_securityContext = null;
ModuleImpl(Logger logger, String id, IModuleDefinition md)
@@ -65,14 +66,73 @@
m_securityContext = securityContext;
}
- public IWire[] getWires()
+ public synchronized IWire[] getWires()
{
return m_wires;
}
- public void setWires(IWire[] wires)
+ public synchronized void setWires(IWire[] wires)
{
+ // Remove module from old wire modules' dependencies.
+ for (int i = 0; (m_wires != null) && (i < m_wires.length); i++)
+ {
+ ((ModuleImpl) m_wires[i].getExporter()).removeDependent(this);
+ }
m_wires = wires;
+ // Add module to new wire modules' dependencies.
+ for (int i = 0; (wires != null) && (i < wires.length); i++)
+ {
+ ((ModuleImpl) m_wires[i].getExporter()).addDependent(this);
+ }
+ }
+
+ public synchronized void addDependent(IModule module)
+ {
+ // Make sure the dependent module is not already present.
+ for (int i = 0; i < m_dependents.length; i++)
+ {
+ if (m_dependents[i].equals(module))
+ {
+ return;
+ }
+ }
+ IModule[] tmp = new IModule[m_dependents.length + 1];
+ System.arraycopy(m_dependents, 0, tmp, 0, m_dependents.length);
+ tmp[m_dependents.length] = module;
+ m_dependents = tmp;
+ }
+
+ public synchronized void removeDependent(IModule module)
+ {
+ // Make sure the dependent module is not already present.
+ for (int i = 0; i < m_dependents.length; i++)
+ {
+ if (m_dependents[i].equals(module))
+ {
+ // If this is the module, then point to empty list.
+ if ((m_dependents.length - 1) == 0)
+ {
+ m_dependents = new IModule[0];
+ }
+ // Otherwise, we need to do some array copying.
+ else
+ {
+ IModule[] tmp = new IModule[m_dependents.length - 1];
+ System.arraycopy(m_dependents, 0, tmp, 0, i);
+ if (i < tmp.length)
+ {
+ System.arraycopy(
+ m_dependents, i + 1, tmp, i, tmp.length - i);
+ }
+ m_dependents = tmp;
+ }
+ }
+ }
+ }
+
+ public synchronized IModule[] getDependents()
+ {
+ return m_dependents;
}
public boolean isRemovalPending()