Fix a deadlock in URLHandlers when Felix.init and Felix.stop are called concurrently (FELIX-4523).

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1609073 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlers.java b/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
index dfe0828..c8fd75a 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
@@ -87,7 +87,7 @@
 
     // This maps classloaders of URLHandlers in other classloaders to lists of
     // their frameworks.
-    private static Map m_classloaderToFrameworkLists = new HashMap();
+    private final static Map m_classloaderToFrameworkLists = new HashMap();
 
     // The list to hold all enabled frameworks registered with this handlers
     private static final List m_frameworks = new ArrayList();
@@ -586,6 +586,7 @@
     **/
     public static void registerFrameworkInstance(Object framework, boolean enable)
     {
+        boolean register = false;
         synchronized (m_frameworks)
         {
             // If the URL Handlers service is not going to be enabled,
@@ -595,13 +596,38 @@
                 // We need to create an instance if this is the first
                 // time this method is called, which will set the handler
                 // factories.
-                if (m_handler == null)
+                if (m_handler == null )
                 {
-                    m_handler = new URLHandlers();
+                    register = true;
                 }
-                m_frameworks.add(framework);
+                else
+                {
+                    m_frameworks.add(framework);
+                    m_counter++;
+                }
             }
-            m_counter++;
+            else
+            {
+                m_counter++;
+            }
+        }
+        if (register)
+        {
+            synchronized (URL.class)
+            {
+                synchronized (m_classloaderToFrameworkLists)
+                {
+                    synchronized (m_frameworks)
+                    {
+                        if (m_handler == null )
+                        {
+                            m_handler = new URLHandlers();
+                        }
+                        m_frameworks.add(framework);
+                        m_counter++;
+                    }
+                }
+            }
         }
     }
 
@@ -618,32 +644,55 @@
         boolean unregister = false;
         synchronized (m_frameworks)
         {
-            m_counter--;
-            if (m_frameworks.remove(framework))
+            if (m_frameworks.contains(framework))
             {
-                if (m_frameworks.isEmpty())
+                if (m_frameworks.size() == 1 && m_handler != null)
                 {
                     unregister = true;
-                    m_handler = null;
                 }
+                else
+                {
+                    m_frameworks.remove(framework);
+                    m_counter--;
+                }
+            }
+            else
+            {
+                m_counter--;
             }
         }
         if (unregister)
         {
-             try
-             {
-                 m_secureAction.invoke(m_secureAction.getDeclaredMethod(
-                     m_rootURLHandlers.getClass(),
-                     "unregisterFrameworkListsForContextSearch",
-                     new Class[]{ ClassLoader.class}),
-                     m_rootURLHandlers,
-                     new Object[] {URLHANDLERS_CLASS.getClassLoader()});
-             }
-             catch (Exception e)
-             {
-                 // This should not happen
-                 e.printStackTrace();
-             }
+            synchronized (URL.class)
+            {
+                synchronized (m_classloaderToFrameworkLists)
+                {
+                    synchronized (m_frameworks)
+                    {
+                        m_frameworks.remove(framework);
+                        m_counter--;
+                        if (m_frameworks.isEmpty() && m_handler != null)
+                        {
+
+                            m_handler = null;
+                            try
+                            {
+                                m_secureAction.invoke(m_secureAction.getDeclaredMethod(
+                                    m_rootURLHandlers.getClass(),
+                                    "unregisterFrameworkListsForContextSearch",
+                                    new Class[]{ ClassLoader.class}),
+                                    m_rootURLHandlers,
+                                    new Object[] {URLHANDLERS_CLASS.getClassLoader()});
+                            }
+                            catch (Exception e)
+                            {
+                                // This should not happen
+                                e.printStackTrace();
+                            }
+                        }
+                    }
+                }
+            }
         }
     }