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()