Modify bundle header cache handling to properly use synchronized block in all
cases when accessing header cache and to use a separate "uninstalled" header
field to hold the default locale headers for uninstalled bundles. (FELIX-3273)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1442600 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 e46e2ff..be8447d 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -58,6 +58,7 @@
     private BundleActivator m_activator = null;
     private volatile BundleContext m_context = null;
     private final Map m_cachedHeaders = new HashMap();
+    private Map m_uninstalledHeaders = null;
     private long m_cachedHeadersTimestamp;
 
     // Indicates whether the bundle is stale, meaning that it has
@@ -186,8 +187,12 @@
             // Reset the bundle state.
             m_state = Bundle.INSTALLED;
             m_stale = false;
-            m_cachedHeaders.clear();
-            m_cachedHeadersTimestamp = 0;
+
+            synchronized (m_cachedHeaders)
+            {
+                m_cachedHeaders.clear();
+                m_cachedHeadersTimestamp = 0;
+            }
         }
     }
 
@@ -345,12 +350,12 @@
         {
             synchronized (m_cachedHeaders)
             {
-                // If the bundle is uninstalled, then the cached headers should
-                // only contain the localized headers for the default locale at
-                // the time of uninstall, so just return that.
-                if (getState() == Bundle.UNINSTALLED)
+                // If the bundle is uninstalled, then we should always return
+                // the uninstalled headers, which are the default locale as per
+                // the spec.
+                if (m_uninstalledHeaders != null)
                 {
-                    result = (Map) m_cachedHeaders.values().iterator().next();
+                    result = m_uninstalledHeaders;
                 }
                 // If the bundle has been updated, clear the cached headers.
                 else if (getLastModified() > m_cachedHeadersTimestamp)
@@ -474,8 +479,11 @@
     {
         synchronized (m_cachedHeaders)
         {
-            m_cachedHeaders.put(locale, localizedHeaders);
-            m_cachedHeadersTimestamp = System.currentTimeMillis();
+            if (m_uninstalledHeaders == null)
+            {
+                m_cachedHeaders.put(locale, localizedHeaders);
+                m_cachedHeadersTimestamp = System.currentTimeMillis();
+            }
         }
     }
 
@@ -1003,11 +1011,10 @@
         // only the default locale will be left in the header cache.
         synchronized (m_cachedHeaders)
         {
-            if ((m_cachedHeaders.size() > 1)
-                || !m_cachedHeaders.containsKey(Locale.getDefault().toString()))
+            if (m_uninstalledHeaders == null)
             {
+                m_uninstalledHeaders = getCurrentLocalizedHeader(Locale.getDefault().toString());
                 m_cachedHeaders.clear();
-                Map map = getCurrentLocalizedHeader(Locale.getDefault().toString());
             }
         }