Handle the fact that fragments can be attached to multiple hosts over
time and thus get additional wires after being resolved. Also, eliminate
host dependency management, since fragment wires provide the same
information. (FELIX-2858)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1080288 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
index 99f0420..1c6e6f5 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -27,7 +27,9 @@
 import org.apache.felix.framework.cache.BundleArchive;
 import org.apache.felix.framework.resolver.Module;
 import org.apache.felix.framework.ext.SecurityProvider;
+import org.apache.felix.framework.resolver.Wire;
 import org.apache.felix.framework.util.StringMap;
+import org.apache.felix.framework.util.Util;
 import org.osgi.framework.*;
 
 class BundleImpl implements Bundle
@@ -473,15 +475,19 @@
         // version instead of the fragment itself. If there are
         // no hosts, but the module is a fragment, then just
         // search the module itself.
-        List<Module> hosts = module.getDependentHosts();
-        if ((hosts != null) && (hosts.size() > 0))
+        if (Util.isFragment(module))
         {
-            module = (ModuleImpl) hosts.get(0);
-            for (int hostIdx = 1; hostIdx < hosts.size(); hostIdx++)
+            List<Wire> hostWires = module.getWires();
+            if ((hostWires != null) && (hostWires.size() > 0))
             {
-                if (module.getVersion().compareTo(hosts.get(hostIdx).getVersion()) < 0)
+                module = (ModuleImpl) hostWires.get(0).getExporter();
+                for (int hostIdx = 1; hostIdx < hostWires.size(); hostIdx++)
                 {
-                    module = (ModuleImpl) hosts.get(hostIdx);
+                    if (module.getVersion().compareTo(
+                        hostWires.get(hostIdx).getExporter().getVersion()) < 0)
+                    {
+                        module = (ModuleImpl) hostWires.get(hostIdx).getExporter();
+                    }
                 }
             }
         }
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 3fbb5a9..b4794d4 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -4221,7 +4221,13 @@
                         }
                     }
 
-                    // Set the module's wires.
+                    // Set the module's wires. If the module is a resolved
+                    // fragment, then we must actually append any new host
+                    // wires to the existing ones.
+                    if (Util.isFragment(module) && module.isResolved())
+                    {
+                        wires.addAll(module.getWires());
+                    }
                     ((ModuleImpl) module).setWires(wires);
 
                     // Attach fragments, if any.
diff --git a/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java b/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
index 9efb88f..26500b0 100644
--- a/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/ModuleImpl.java
@@ -35,6 +35,7 @@
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -98,7 +99,6 @@
 
     private List<Module> m_fragments = null;
     private List<Wire> m_wires = null;
-    private List<Module> m_dependentHosts = new ArrayList<Module>(0);
     private List<Module> m_dependentImporters = new ArrayList<Module>(0);
     private List<Module> m_dependentRequirers = new ArrayList<Module>(0);
     private volatile boolean m_isResolved = false;
@@ -472,10 +472,9 @@
         // the dependencies this module has on other modules (i.e., the provider
         // end of the wire) to simplify bookkeeping.
 
-        // Fragments don't depend on other their hosts, so we just record the
-        // wires for informational purposes.
-// TODO: FRAGMENT RESOLVER - It is possible for a fragment to get more wires
-//       later if it is attached to more hosts. We need to deal with that.
+        // For fragments we don't need to capture any additional dependency
+        // information, since the wires are sufficient, so just record the
+        // new wires. The wires are to the hosts to which the fragment is attached.
         boolean isFragment = Util.isFragment(this);
 
         // Remove module from old wire modules' dependencies,
@@ -1176,12 +1175,22 @@
 
     public synchronized void attachFragments(List<Module> fragments) throws Exception
     {
-        // Remove module from old fragment dependencies.
-        // We will generally only remove module fragment
-        // dependencies when we are uninstalling the module.
+        // Remove the host wires for this module from old fragments.
+        // We will generally only remove host wires when we are uninstalling
+        // the module.
         for (int i = 0; (m_fragments != null) && (i < m_fragments.size()); i++)
         {
-            ((ModuleImpl) m_fragments.get(i)).removeDependentHost(this);
+            List<Wire> hostWires = new ArrayList<Wire>(m_fragments.get(i).getWires());
+            for (Iterator<Wire> it = hostWires.iterator(); it.hasNext(); )
+            {
+                Wire hostWire = it.next();
+                if (hostWire.getExporter().equals(this))
+                {
+                    it.remove();
+                    ((ModuleImpl) m_fragments.get(i)).setWires(hostWires);
+                    break;
+                }
+            }
         }
 
         // Close previous fragment contents.
@@ -1232,7 +1241,6 @@
             m_fragmentContents = new Content[m_fragments.size()];
             for (int i = 0; (m_fragments != null) && (i < m_fragments.size()); i++)
             {
-                ((ModuleImpl) m_fragments.get(i)).addDependentHost(this);
                 m_fragmentContents[i] =
                     m_fragments.get(i).getContent()
                         .getEntryAsContent(FelixConstants.CLASS_PATH_DOT);
@@ -1242,24 +1250,6 @@
         }
     }
 
-    public synchronized List<Module> getDependentHosts()
-    {
-        return m_dependentHosts;
-    }
-
-    public synchronized void addDependentHost(Module module)
-    {
-        if (!m_dependentHosts.contains(module))
-        {
-            m_dependentHosts.add(module);
-        }
-    }
-
-    public synchronized void removeDependentHost(Module module)
-    {
-        m_dependentHosts.remove(module);
-    }
-
     public synchronized List<Module> getDependentImporters()
     {
         return m_dependentImporters;
@@ -1298,11 +1288,22 @@
 
     public synchronized List<Module> getDependents()
     {
-        List<Module> dependents = new ArrayList<Module>
-            (m_dependentHosts.size() + m_dependentImporters.size() + m_dependentRequirers.size());
-        dependents.addAll(m_dependentHosts);
-        dependents.addAll(m_dependentImporters);
-        dependents.addAll(m_dependentRequirers);
+        List<Module> dependents;
+        if (Util.isFragment(this))
+        {
+            dependents = new ArrayList<Module>();
+            for (int i = 0; (m_wires != null) && (i < m_wires.size()); i++)
+            {
+                dependents.add(m_wires.get(i).getExporter());
+            }
+        }
+        else
+        {
+            dependents = new ArrayList<Module>
+                (m_dependentImporters.size() + m_dependentRequirers.size());
+            dependents.addAll(m_dependentImporters);
+            dependents.addAll(m_dependentRequirers);
+        }
         return dependents;
     }
 
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 00f7e5a..09ac0bc 100644
--- a/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java
@@ -20,9 +20,11 @@
 
 import java.util.*;
 import org.apache.felix.framework.resolver.Module;
+import org.apache.felix.framework.resolver.Wire;
 import org.apache.felix.framework.util.VersionRange;
 import org.osgi.framework.AdminPermission;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.Version;
 import org.osgi.service.packageadmin.ExportedPackage;
@@ -234,10 +236,10 @@
                 ModuleImpl module = (ModuleImpl) modules.get(modIdx);
                 if (module.isResolved())
                 {
-                    List<Module> hosts = module.getDependentHosts();
-                    for (int i = 0; (hosts != null) && (i < hosts.size()); i++)
+                    List<Wire> hostWires = module.getWires();
+                    for (int i = 0; (hostWires != null) && (i < hostWires.size()); i++)
                     {
-                        Bundle b = hosts.get(i).getBundle();
+                        Bundle b = hostWires.get(i).getExporter().getBundle();
                         if (b != null)
                         {
                             list.add(b);
@@ -246,7 +248,7 @@
                 }
             }
             // Convert list to an array.
-            return (list.size() == 0)
+            return (list.isEmpty())
                 ? null
                 : (Bundle[]) list.toArray(new Bundle[list.size()]);
         }