Applied patch (FELIX-170) to stop the start level and package admin threads
when the framework shuts down.


git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@472013 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/PackageAdminActivator.java b/framework/src/main/java/org/apache/felix/framework/PackageAdminActivator.java
index ec78129..5e9175e 100644
--- a/framework/src/main/java/org/apache/felix/framework/PackageAdminActivator.java
+++ b/framework/src/main/java/org/apache/felix/framework/PackageAdminActivator.java
@@ -24,6 +24,7 @@
 {
     private Felix m_felix = null;
     private ServiceRegistration m_reg = null;
+    private PackageAdminImpl m_packageAdmin = null;
 
     public PackageAdminActivator(Felix felix)
     {
@@ -32,13 +33,15 @@
 
     public void start(BundleContext context) throws Exception
     {
+        m_packageAdmin = new PackageAdminImpl(m_felix);
         m_reg = context.registerService(
             org.osgi.service.packageadmin.PackageAdmin.class.getName(),
-            new PackageAdminImpl(m_felix), null);
+            m_packageAdmin, null);
     }
 
     public void stop(BundleContext context) throws Exception
     {
         m_reg.unregister();
+        m_packageAdmin.stop();
     }
 }
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java b/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java
index 9c6a6f6..56148c3 100644
--- a/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java
@@ -29,6 +29,7 @@
     private Felix m_felix = null;
     private Bundle[][] m_reqBundles = null;
     private Bundle m_systemBundle = null;
+    private Thread m_thread = null;
 
     public PackageAdminImpl(Felix felix)
     {
@@ -36,12 +37,35 @@
         m_systemBundle = m_felix.getBundle(0);
 
         // Start a thread to perform asynchronous package refreshes.
-        Thread t = new Thread(this, "FelixPackageAdmin");
-        t.setDaemon(true);
-        t.start();
+        m_thread = new Thread(this, "FelixPackageAdmin");
+        m_thread.setDaemon(true);
+        m_thread.start();
     }
 
     /**
+     * Stops the FelixPackageAdmin thread on system shutdown. Shutting down the
+     * thread explicitly is required in the embedded case, where Felix may be
+     * stopped without the Java VM being stopped. In this case the
+     * FelixPackageAdmin thread must be stopped explicitly.
+     * <p>
+     * This method is called by the
+     * {@link PackageAdminActivator#stop(BundleContext)} method.
+     */
+    synchronized void stop()
+    {
+        if (m_thread != null)
+        {
+            // Null thread variable to signal to the thread that
+            // we want it to exit.
+            m_thread = null;
+            
+            // Wake up the thread, if it is currently in the wait() state
+            // for more work.
+            notifyAll();
+        }
+    }
+    
+    /**
      * Returns the bundle associated with this class if the class was
      * loaded from a bundle, otherwise returns null.
      * 
@@ -210,6 +234,12 @@
                 // Wait for a refresh request.
                 while (m_reqBundles == null)
                 {
+                    // Terminate the thread if requested to do so (see stop()).
+                    if (m_thread == null)
+                    {
+                        return;
+                    }
+                    
                     try
                     {
                         wait();
diff --git a/framework/src/main/java/org/apache/felix/framework/StartLevelActivator.java b/framework/src/main/java/org/apache/felix/framework/StartLevelActivator.java
index 20b7970..61e8046 100644
--- a/framework/src/main/java/org/apache/felix/framework/StartLevelActivator.java
+++ b/framework/src/main/java/org/apache/felix/framework/StartLevelActivator.java
@@ -23,6 +23,7 @@
 class StartLevelActivator implements BundleActivator
 {
     private Felix m_felix = null;
+    private StartLevelImpl m_startLevel = null;
     private ServiceRegistration m_reg = null;
 
     public StartLevelActivator(Felix felix)
@@ -32,13 +33,15 @@
 
     public void start(BundleContext context) throws Exception
     {
+        m_startLevel = new StartLevelImpl(m_felix);
         m_reg = context.registerService(
             org.osgi.service.startlevel.StartLevel.class.getName(),
-            new StartLevelImpl(m_felix), null);
+            m_startLevel, null);
     }
 
     public void stop(BundleContext context) throws Exception
     {
         m_reg.unregister();
+        m_startLevel.stop();
     }
 }
diff --git a/framework/src/main/java/org/apache/felix/framework/StartLevelImpl.java b/framework/src/main/java/org/apache/felix/framework/StartLevelImpl.java
index ad6d7cd..5be90ff 100644
--- a/framework/src/main/java/org/apache/felix/framework/StartLevelImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/StartLevelImpl.java
@@ -39,16 +39,43 @@
     private Felix m_felix = null;
     private List m_requestList = null;
     private Bundle m_systemBundle = null;
-    
+    private Thread m_thread = null;
+
     public StartLevelImpl(Felix felix)
     {
         m_felix = felix;
         m_requestList = new ArrayList();
         m_systemBundle = m_felix.getBundle(0);
         // Start a thread to perform asynchronous package refreshes.
-        Thread t = new Thread(this, "FelixStartLevel");
-        t.setDaemon(true);
-        t.start();
+        m_thread = new Thread(this, "FelixStartLevel");
+        m_thread.setDaemon(true);
+        m_thread.start();
+    }
+    
+    /**
+     * Stops the FelixStartLevel thread on system shutdown. Shutting down the
+     * thread explicitly is required in the embedded case, where Felix may be
+     * stopped without the Java VM being stopped. In this case the
+     * FelixStartLevel thread must be stopped explicitly.
+     * <p>
+     * This method is called by the
+     * {@link StartLevelActivator#stop(BundleContext)} method.
+     */
+    void stop()
+    {
+        synchronized (m_requestList)
+        {
+            if (m_thread != null)
+            {
+                // Null thread variable to signal to the thread that
+                // we want it to exit.
+                m_thread = null;
+                
+                // Wake up the thread, if it is currently in the wait() state
+                // for more work.
+                m_requestList.notifyAll();
+            }
+        }
     }
     
     /* (non-Javadoc)
@@ -199,6 +226,12 @@
                 // Wait for a request.
                 while (m_requestList.size() == 0)
                 {
+                    // Terminate the thread if requested to do so (see stop()).
+                    if (m_thread == null)
+                    {
+                        return;
+                    }
+                    
                     try
                     {
                         m_requestList.wait();