More modifications for fragment support. Properly manages fragment
dependencies so that they are managed properly during the update/refresh
cycle. (FELIX-656)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@686513 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 223809a..74574f1 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -427,7 +427,12 @@
 
     public String toString()
     {
-        return m_felix.getBundleSymbolicName(this) + " [" + getBundleId() +"]";
+        String sym = m_felix.getBundleSymbolicName(this);
+        if (sym != null)
+        {
+            return m_felix.getBundleSymbolicName(this) + " [" + getBundleId() +"]";
+        }
+        return "[" + getBundleId() +"]";
     }
 
     Object getSignerMatcher()
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 b446e48..dc40d8f 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -3225,7 +3225,6 @@
     {
         // Acquire locks for all impacted bundles.
         FelixBundle[] bundles = acquireBundleRefreshLocks(targets);
-
         boolean restart = false;
 
         Bundle systemBundle = getBundle(0);
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java
index ff12f9d..dc08875 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java
@@ -41,7 +41,7 @@
     private final Logger m_logger;
     private final IContent m_content;
     private IContent[] m_contentPath;
-    private IContent[] m_fragments = null;
+    private IContent[] m_fragmentContents = null;
     private ISearchPolicy m_searchPolicy = null;
     private IURLPolicy m_urlPolicy = null;
     private ContentClassLoader m_classLoader;
@@ -66,6 +66,10 @@
         {
             m_contentPath[i].close();
         }
+        for (int i = 0; (m_fragmentContents != null) && (i < m_fragmentContents.length); i++)
+        {
+            m_fragmentContents[i].close();
+        }
     }
 
     public IContent getContent()
@@ -89,23 +93,27 @@
         return m_contentPath;
     }
 
-    public synchronized void setFragmentContents(IContent[] contents) throws Exception
+    public synchronized void attachFragmentContents(IContent[] fragmentContents)
+        throws Exception
     {
-        m_fragments = contents;
-// TODO: FRAGMENT - If this is not null, then we probably need to close
-//       the existing contents; this might happen when a resource is loaded
-//       from a bundle that could not be resolved.
-if (m_contentPath != null)
-{
-m_logger.log(Logger.LOG_DEBUG, "(FRAGMENT) CONTENT PATH SHOULD BE NULL = " + m_contentPath);
-}
+        // Close existing fragment contents.
+        if (m_fragmentContents != null)
+        {
+            for (int i = 0; i < m_fragmentContents.length; i++)
+            {
+                m_fragmentContents[i].close();
+            }
+        }
+        m_fragmentContents = fragmentContents;
+
+        if (m_contentPath != null)
+        {
+            for (int i = 0; i < m_contentPath.length; i++)
+            {
+                m_contentPath[i].close();
+            }
+        }
         m_contentPath = initializeContentPath();
-String msg = "(FRAGMENT) HOST CLASSPATH = ";
-for (int i = 0; i < m_contentPath.length; i++)
-{
-    msg += (m_contentPath[i].toString() + " ");
-}
-m_logger.log(Logger.LOG_DEBUG, msg);
     }
 
     public synchronized void setSearchPolicy(ISearchPolicy searchPolicy)
@@ -301,9 +309,9 @@
     {
         List contentList = new ArrayList();
         calculateContentPath(m_content, contentList, true);
-        for (int i = 0; (m_fragments != null) && (i < m_fragments.length); i++)
+        for (int i = 0; (m_fragmentContents != null) && (i < m_fragmentContents.length); i++)
         {
-            calculateContentPath(m_fragments[i], contentList, false);
+            calculateContentPath(m_fragmentContents[i], contentList, false);
         }
         return (IContent[]) contentList.toArray(new IContent[contentList.size()]);
     }
@@ -365,10 +373,10 @@
                 // so try to search the fragments if necessary.
                 for (int fragIdx = 0;
                     searchFragments && (embeddedContent == null)
-                        && (m_fragments != null) && (fragIdx < m_fragments.length);
+                        && (m_fragmentContents != null) && (fragIdx < m_fragmentContents.length);
                     fragIdx++)
                 {
-                    embeddedContent = m_fragments[fragIdx].getEntryAsContent(classPathStrings[i]);
+                    embeddedContent = m_fragmentContents[fragIdx].getEntryAsContent(classPathStrings[i]);
                 }
                 // If we found the embedded content, then add it to the
                 // class path content list.
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 9fddfa1..e4786fe 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
@@ -1034,12 +1034,6 @@
                 targetFragment = rootModule;
                 List hostList = getPotentialHosts(targetFragment);
                 rootModule = (IModule) hostList.get(0);
-String msg = "(FRAGMENT) POSSILE HOST(S): ";
-for (int i = 0; i < hostList.size(); i++)
-{
-    msg += (hostList.get(i).toString() + " ");
-}
-m_logger.log(Logger.LOG_DEBUG, msg);
             }
 
             // Get the available fragments for the host.
@@ -1060,7 +1054,7 @@
     String symName = (String) entry.getKey();
     IModule[] fragments = (IModule[]) entry.getValue();
     m_logger.log(Logger.LOG_DEBUG, "(FRAGMENT) WIRE: "
-        + rootModule + " -> " + symName + "[" + fragments.length + "] -> " + fragments[0]);
+        + rootModule + " -> " + symName + " -> " + fragments[0]);
 }
 
             // This variable maps an unresolved module to a list of candidate
@@ -1113,14 +1107,13 @@
                 {
                     Map.Entry entry = (Map.Entry) iter.next();
                     IModule[] fragments = (IModule[]) entry.getValue();
-                    list.add(fragments[0].getContentLoader().getContent()
-                        .getEntryAsContent(FelixConstants.CLASS_PATH_DOT));
+// TODO: FRAGMENT - For now, just attach first candidate.
+                    list.add(fragments[0]);
                 }
                 try
                 {
-                    ((ContentLoaderImpl) rootModule.getContentLoader())
-                        .setFragmentContents(
-                            (IContent[]) list.toArray(new IContent[list.size()]));
+                    ((ModuleImpl) rootModule).attachFragments(
+                        (IModule[]) list.toArray(new IModule[list.size()]));
                 }
                 catch (Exception ex)
                 {
@@ -2944,6 +2937,16 @@
                 }
             }
 
+            // Set fragments to null, which will remove the module from all
+            // of its dependent fragment modules.
+            try
+            {
+                ((ModuleImpl) event.getModule()).attachFragments(null);
+            }
+            catch (Exception ex)
+            {
+                m_logger.log(Logger.LOG_ERROR, "Error detaching fragments.", ex);
+            }
             // Set wires to null, which will remove the module from all
             // of its dependent modules.
             ((ModuleImpl) event.getModule()).setWires(null);
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 32d50cb..43757a2 100644
--- a/framework/src/main/java/org/apache/felix/moduleloader/ModuleImpl.java
+++ b/framework/src/main/java/org/apache/felix/moduleloader/ModuleImpl.java
@@ -22,6 +22,8 @@
 import java.util.Enumeration;
 
 import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.searchpolicy.ContentLoaderImpl;
+import org.apache.felix.framework.util.FelixConstants;
 
 public class ModuleImpl implements IModule
 {
@@ -30,6 +32,7 @@
     private boolean m_removalPending = false;
     private IModuleDefinition m_md = null;
     private IContentLoader m_contentLoader = null;
+    private IModule[] m_fragments = null;
     private IWire[] m_wires = null;
     private IModule[] m_dependents = new IModule[0];
 
@@ -60,6 +63,36 @@
         m_contentLoader = contentLoader;
     }
 
+    public synchronized void attachFragments(IModule[] fragments) throws Exception
+    {
+        // Remove module from old fragment dependencies.
+        // We will generally only remove module fragment
+        // dependencies when we are uninstalling the module.
+        for (int i = 0; (m_fragments != null) && (i < m_fragments.length); i++)
+        {
+            ((ModuleImpl) m_fragments[i]).removeDependent(this);
+        }
+
+        // Update the dependencies on the new fragments.
+        m_fragments = fragments;
+        if (m_fragments != null)
+        {
+            // We need to add ourself as a dependent of each fragment
+            // module. We also need to create an array of fragment contents
+            // to attach to our content loader.
+            IContent[] fragmentContents = new IContent[m_fragments.length];
+            for (int i = 0; (m_fragments != null) && (i < m_fragments.length); i++)
+            {
+                ((ModuleImpl) m_fragments[i]).addDependent(this);
+                fragmentContents[i] =
+                    m_fragments[i].getContentLoader().getContent()
+                        .getEntryAsContent(FelixConstants.CLASS_PATH_DOT);
+            }
+            // Now attach the fragment contents to our content loader.
+            ((ContentLoaderImpl) m_contentLoader).attachFragmentContents(fragmentContents);
+        }
+    }
+
     public synchronized IWire[] getWires()
     {
         return m_wires;
@@ -80,7 +113,7 @@
         }
     }
 
-    public synchronized void addDependent(IModule module)
+    private synchronized void addDependent(IModule module)
     {
         // Make sure the dependent module is not already present.
         for (int i = 0; i < m_dependents.length; i++)
@@ -96,7 +129,7 @@
         m_dependents = tmp;
     }
 
-    public synchronized void removeDependent(IModule module)
+    private synchronized void removeDependent(IModule module)
     {
         // Make sure the dependent module is not already present.
         for (int i = 0; i < m_dependents.length; i++)