FELIX-2557 Further work on event dispatching: ConfigurationManager now uses two separate threads to dispatch configuration events and configuration updates. Both threads are configured to be members of their own thread group, which is a daemon group to be destroyed once both dispatcher threads terminate.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@989533 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
index 860dbc5..52abff7 100644
--- a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
+++ b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
@@ -122,6 +122,9 @@
     // the thread used to schedule tasks required to run asynchronously
     private UpdateThread updateThread;
 
+    // the thread used to schedule events to be dispatched asynchronously
+    private UpdateThread eventThread;
+
     /**
      * The actual list of {@link PersistenceManager persistence managers} to use
      * when looking for configuration data. This list is built from the
@@ -192,8 +195,10 @@
         configurationListenerTracker.open();
 
         // initialize the asynchonous updater thread
-        this.updateThread = new UpdateThread( this );
-        this.updateThread.start();
+        ThreadGroup tg = new ThreadGroup( "Configuration Admin Service" );
+        tg.setDaemon( true );
+        this.updateThread = new UpdateThread( this, tg, "CM Configuration Updater" );
+        this.eventThread = new UpdateThread( this, tg, "CM Event Dispatcher" );
 
         // set up the location (might throw IllegalArgumentException)
         try
@@ -275,18 +280,12 @@
 
         if ( updateThread != null )
         {
-            // terminate asynchrounous updates
             updateThread.terminate();
+        }
 
-            // wait for all updates to terminate
-            try
-            {
-                updateThread.join();
-            }
-            catch ( InterruptedException ie )
-            {
-                // don't really care
-            }
+        if ( eventThread != null )
+        {
+            eventThread.terminate();
         }
 
         if ( logTracker != null )
@@ -590,7 +589,7 @@
         FireConfigurationEvent event = new FireConfigurationEvent( type, pid, factoryPid );
         if ( event.hasConfigurationEventListeners() )
         {
-            updateThread.schedule( event );
+            eventThread.schedule( event );
         }
         else if ( isLogEnabled( LogService.LOG_DEBUG ) )
         {
diff --git a/configadmin/src/main/java/org/apache/felix/cm/impl/UpdateThread.java b/configadmin/src/main/java/org/apache/felix/cm/impl/UpdateThread.java
index 562036b..f68cc6c 100644
--- a/configadmin/src/main/java/org/apache/felix/cm/impl/UpdateThread.java
+++ b/configadmin/src/main/java/org/apache/felix/cm/impl/UpdateThread.java
@@ -28,27 +28,32 @@
  * The <code>UpdateThread</code> is the thread used to update managed services
  * and managed service factories as well as to send configuration events.
  */
-public class UpdateThread extends Thread
+public class UpdateThread implements Runnable
 {
 
-    // the base name of the thread which is set while there is no
-    // task to run
-    private static final String BASE_THREAD_NAME = "Configuration Updater";
-
     // the configuration manager on whose behalf this thread is started
     // (this is mainly used for logging)
-    private ConfigurationManager configurationManager;
+    private final ConfigurationManager configurationManager;
+
+    // the thread's base name
+    private final String workerBaseName;
 
     // the queue of Runnable instances  to be run
-    private LinkedList updateTasks;
+    private final LinkedList updateTasks;
+
+    // the actual thread
+    private final Thread worker;
 
 
-    public UpdateThread( ConfigurationManager configurationManager )
+    public UpdateThread( final ConfigurationManager configurationManager, final ThreadGroup tg, final String name )
     {
-        super( BASE_THREAD_NAME );
-
         this.configurationManager = configurationManager;
+        this.workerBaseName = name;
+
         this.updateTasks = new LinkedList();
+        this.worker = new Thread( tg, this, name );
+        this.worker.setDaemon( true );
+        this.worker.start();
     }
 
 
@@ -89,7 +94,7 @@
             try
             {
                 // set the thread name indicating the current task
-                setName( BASE_THREAD_NAME + " (" + task + ")" );
+                worker.setName( workerBaseName + " (" + task + ")" );
 
                 if ( configurationManager.isLogEnabled( LogService.LOG_DEBUG ) )
                 {
@@ -105,17 +110,27 @@
             finally
             {
                 // reset the thread name to "idle"
-                setName( BASE_THREAD_NAME );
+                worker.setName( workerBaseName );
             }
         }
     }
 
 
     // cause this thread to terminate by adding this thread to the end
-    // of the queue
+    // of the queue and wait for the thread to actually terminate
     void terminate()
     {
         schedule( this );
+
+        // wait for all updates to terminate
+        try
+        {
+            worker.join();
+        }
+        catch ( InterruptedException ie )
+        {
+            // don't really care
+        }
     }