Cache results for System Bundle from PackageAdmin.getBundle() in a
weak hash map. (FELIX-2805)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1064879 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 33d3c2d..33dcbfe 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -749,6 +749,14 @@
                 // Now that the system bundle is successfully created we can give
                 // its bundle context to the logger so that it can track log services.
                 m_logger.setSystemBundleContext(_getBundleContext());
+
+                // Clear the cache of classes coming from the system bundle.
+                // This is only used for Felix.getBundle(Class clazz) to speed
+                // up class lookup for the system bundle.
+                synchronized (m_systemBundleClassCache)
+                {
+                    m_systemBundleClassCache.clear();
+                }
             }
         }
         finally
@@ -3040,6 +3048,9 @@
     // PackageAdmin related methods.
     //
 
+    private final Map<Class, Boolean> m_systemBundleClassCache =
+        new WeakHashMap<Class, Boolean>();
+
     /**
      * This method returns the bundle associated with the specified class if
      * the class was loaded from a bundle from this framework instance. If the
@@ -3053,6 +3064,8 @@
     **/
     Bundle getBundle(Class clazz)
     {
+        // If the class comes from bundle class loader, then return
+        // associated bundle if it is from this framework instance.
         if (clazz.getClassLoader() instanceof BundleReference)
         {
             // Only return the bundle if it is from this framework.
@@ -3061,19 +3074,41 @@
                 && (((BundleImpl) br.getBundle()).getFramework() == this))
                     ? br.getBundle() : null;
         }
-        try
+        // Otherwise check if the class conceptually comes from the
+        // system bundle. Ignore implicit boot delegation.
+        if (!clazz.getName().startsWith("java."))
         {
-            // For implicit boot delegation, we don't want those classes
-            // to be shown as coming from the system bundle.
-            if (!clazz.getName().startsWith("java."))
+            Boolean fromSystemBundle;
+            synchronized (m_systemBundleClassCache)
             {
-                return (m_extensionManager.getModule().getClassByDelegation(clazz.getName()) == clazz)
-                    ? this : null;
+                fromSystemBundle = m_systemBundleClassCache.get(clazz);
             }
-        }
-        catch(ClassNotFoundException ex)
-        {
-            // Ignore and return null.
+            if (fromSystemBundle == null)
+            {
+                Class sbClass = null;
+                try
+                {
+                    sbClass = m_extensionManager
+                        .getModule().getClassByDelegation(clazz.getName());
+                }
+                catch (ClassNotFoundException ex)
+                {
+                    // Ignore, treat as false.
+                }
+                synchronized (m_systemBundleClassCache)
+                {
+                    if (sbClass == clazz)
+                    {
+                        fromSystemBundle = Boolean.TRUE;
+                    }
+                    else
+                    {
+                        fromSystemBundle = Boolean.FALSE;
+                    }
+                    m_systemBundleClassCache.put(clazz, fromSystemBundle);
+                }
+            }
+            return fromSystemBundle.booleanValue() ? this : null;
         }
         return null;
     }