Fix bundle refreshing of native libraries. (FELIX-2990)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1134338 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 105e6cb..ab9a644 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -2663,7 +2663,10 @@
                 // due to an error or system crash.
                 try
                 {
-                    ba.purge();
+                    if (ba.isRemovalPending())
+                    {
+                        ba.purge();
+                    }
                 }
                 catch (Exception ex)
                 {
@@ -3572,6 +3575,9 @@
                     // resolved exporters of the package.
                     if (cap.getNamespace().equals(BundleRevision.PACKAGE_NAMESPACE))
                     {
+// TODO: OSGi R4.3 - We can probably do this in a more efficient way once
+//       BundleWiring.getCapabilities() returns the proper result. We probably
+//       Won't even need this method.
                         String pkgName = (String)
                             cap.getAttributes().get(BundleCapabilityImpl.PACKAGE_ATTR);
                         Map<String, Object> attrs = new HashMap<String, Object>(1);
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java b/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
index af26209..4f0d6bf 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
@@ -25,6 +25,7 @@
 import java.util.TreeMap;
 import org.apache.felix.framework.Logger;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
 
 /**
  * <p>
@@ -490,15 +491,9 @@
         return (m_revisions.isEmpty()) ? null : m_revisions.get(m_revisions.lastKey());
     }
 
-    /**
-     * <p>
-     * Returns the revision object for the specified revision.
-     * </p>
-     * @return the revision object for the specified revision.
-    **/
-    public synchronized BundleRevision getRevision(Long l)
+    public synchronized boolean isRemovalPending()
     {
-        return m_revisions.get(l);
+        return (m_revisions.size() > 1);
     }
 
     /**
@@ -700,21 +695,24 @@
     **/
     public synchronized void purge() throws Exception
     {
-        if (m_revisions.size() > 1)
+        // Remember current revision number.
+        Long currentRevNum = getCurrentRevisionNumber();
+
+        // Record whether the current revision has native libraries, which
+        // we'll use later to determine if we need to rename its directory.
+        boolean hasNativeLibs = getCurrentRevision().getManifestHeader()
+            .containsKey(Constants.BUNDLE_NATIVECODE);
+
+        // Close all revisions and then delete all but the current revision.
+        // We don't delete it the current revision, because we want to rename it
+        // to the new refresh level.
+        close();
+
+        // Delete all old revisions.
+        long refreshCount = getRefreshCount();
+        for (Long revNum : m_revisions.keySet())
         {
-            // Close the revisions and then delete all but the current revision.
-            // We don't delete it the current revision, because we want to rename it
-            // to the new refresh level.
-            close();
-
-            // Remove the current revision from the revision map so it doesn't
-            // get deleted.
-            Long currentRevNum = m_revisions.lastKey();
-            m_revisions.remove(currentRevNum);
-
-            // Delete all old revisions.
-            long refreshCount = getRefreshCount();
-            for (Long revNum : m_revisions.keySet())
+            if (!revNum.equals(currentRevNum))
             {
                 File revisionDir = new File(
                     m_archiveRootDir,
@@ -724,7 +722,13 @@
                     BundleCache.deleteDirectoryTree(revisionDir);
                 }
             }
+        }
 
+        // If the revision has native libraries, then rename its directory
+        // to avoid the issue of being unable to load the same native library
+        // into two different class loaders.
+        if (hasNativeLibs)
+        {
             // Increment the refresh count.
             setRefreshCount(refreshCount + 1);
 
@@ -734,16 +738,16 @@
             File revisionDir = new File(m_archiveRootDir,
                 REVISION_DIRECTORY + refreshCount + "." + currentRevNum.toString());
             BundleCache.getSecureAction().renameFile(revisionDir, currentDir);
-
-            // Clear the revision map since they are all invalid now.
-            m_revisions.clear();
-
-            // Recreate the revision for the current location.
-            BundleRevision revision = createRevisionFromLocation(
-                getRevisionLocation(currentRevNum), null, currentRevNum);
-            // Add new revision to the revision map.
-            m_revisions.put(currentRevNum, revision);
         }
+
+        // Clear the revision map since they are all invalid now.
+        m_revisions.clear();
+
+        // Recreate the revision for the current location.
+        BundleRevision revision = createRevisionFromLocation(
+            getRevisionLocation(currentRevNum), null, currentRevNum);
+        // Add new revision to the revision map.
+        m_revisions.put(currentRevNum, revision);
     }
 
     /**
@@ -890,19 +894,19 @@
 
     // Method from Harmony java.net.URIEncoderDecoder (luni subproject)
     // used by URI to decode uri components.
-    private static String decode(String s) throws UnsupportedEncodingException 
+    private static String decode(String s) throws UnsupportedEncodingException
     {
         StringBuffer result = new StringBuffer();
         ByteArrayOutputStream out = new ByteArrayOutputStream();
-        for (int i = 0; i < s.length();) 
+        for (int i = 0; i < s.length();)
         {
             char c = s.charAt(i);
-            if (c == '%') 
+            if (c == '%')
             {
                 out.reset();
-                do 
+                do
                 {
-                    if ((i + 2) >= s.length()) 
+                    if ((i + 2) >= s.length())
                     {
                         throw new IllegalArgumentException(
                             "Incomplete % sequence at: " + i);