Modified the bundle archive implementation to reconstruct old bundle
revisions if they exist in the file system on startup. Such a situation
occurs if a bundle was updated and the framework uncleanly exited before
a refresh was performed. By recreating the existing revisions, the
framework will force a purge at startup to delete the old revision
directories and only keep the most recent revision (just as if a normal
refresh has occurred instead of an unclean exit in the previous session).


git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@405419 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
index e5f6fbf..5c1d24c 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
@@ -157,7 +157,40 @@
         m_logger = logger;
         m_archiveRootDir = archiveRootDir;
 
-        // Add a revision for the content.
+        // Add a revision for each one that already exists in the file
+        // system. The file system might contain more than one revision
+        // if the bundle was updated in a previous session, but the
+        // framework was not refreshed; this might happen if the framework
+        // did not exit cleanly. We must create the existing revisions so
+        // that they can be properly purged.
+        int revisionCount = 0;
+        while (true)
+        {
+            // Count the number of existing revision directories, which
+            // will be in a directory named like:
+            //     "${REVISION_DIRECTORY)${refresh-count}.${revision-count}"
+            File revisionRootDir = new File(m_archiveRootDir,
+                REVISION_DIRECTORY + getRefreshCount() + "." + revisionCount);
+            if (!BundleCache.getSecureAction().fileExists(revisionRootDir))
+            {
+                break;
+            }
+
+            // Increment the revision count.
+            revisionCount++;
+        }
+
+        // If there are multiple revisions in the file system, then create
+        // an array that is big enough to hold all revisions minus one; the
+        // call below to revise() will add the most recent revision. NOTE: We
+        // do not actually need to add a real revision object for the older
+        // revisions since they will be purged immediately on framework startup.
+        if (revisionCount > 1)
+        {
+            m_revisions = new BundleRevision[revisionCount - 1];
+        }
+
+        // Add the revision object for the most recent revision.
         revise(getCurrentLocation(), null);
     }
 
@@ -619,7 +652,14 @@
         File revisionDir = null;
         for (int i = 0; i < count - 1; i++)
         {
-            m_revisions[i].dispose();
+            // Dispose of the revision, but this might be null in certain
+            // circumstances, such as if this bundle archive was created
+            // for an existing bundle that was updated, but not refreshed
+            // due to a system crash; see the constructor code for details.
+            if (m_revisions[i] != null)
+            {
+                m_revisions[i].dispose();
+            }
             revisionDir = new File(m_archiveRootDir, REVISION_DIRECTORY + refreshCount + "." + i);
             if (BundleCache.getSecureAction().fileExists(revisionDir))
             {
@@ -797,7 +837,7 @@
     private BundleRevision createRevisionFromLocation(String location, InputStream is)
         throws Exception
     {
-        // The revision directory is name using the refresh count and
+        // The revision directory is named using the refresh count and
         // the revision count. The revision count is obvious, but the
         // refresh count is less obvious. This is necessary due to how
         // native libraries are handled in Java; needless to say, every
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
index cbba4b1..22423b6 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
@@ -259,7 +259,7 @@
                 return;
             }
 
-            // Create revision directory, if it does not exist.
+            // Create revision directory.
             if (!BundleCache.getSecureAction().mkdir(getRevisionRootDir()))
             {
                 getLogger().log(
@@ -297,7 +297,6 @@
                 BundleCache.copyStreamToFile(is, m_bundleFile);
             }
 
-            // This will always be revision zero.
             preprocessBundleJar();
         }
         finally