FELIX-1716: Fileinstall does not properly handle bundles uninstalled through the OSGi API

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@825165 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
index 26aab3c..c838ad4 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
@@ -43,7 +43,9 @@
 import org.apache.felix.fileinstall.ArtifactUrlTransformer;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
 import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
 import org.osgi.framework.Constants;
 import org.osgi.service.packageadmin.PackageAdmin;
 
@@ -70,7 +72,7 @@
  *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public class DirectoryWatcher extends Thread
+public class DirectoryWatcher extends Thread implements BundleListener
 {
 	public final static String FILENAME = "felix.fileinstall.filename";
     public final static String POLL = "felix.fileinstall.poll";
@@ -116,6 +118,7 @@
         startBundles = getBoolean(properties, START_NEW_BUNDLES, true);  // by default, we start bundles.
         filter = (String) properties.get(FILTER);
         noInitialDelay = getBoolean(properties, NO_INITIAL_DELAY, false);
+        this.context.addBundleListener(this);
 
         FilenameFilter flt;
         if (filter != null && filter.length() > 0)
@@ -199,6 +202,24 @@
         }
     }
 
+    public void bundleChanged(BundleEvent bundleEvent)
+    {
+        if (bundleEvent.getType() == BundleEvent.UNINSTALLED)
+        {
+            for (Iterator it = currentManagedArtifacts.entrySet().iterator(); it.hasNext();)
+            {
+                Map.Entry entry = (Map.Entry) it.next();
+                Artifact artifact = (Artifact) entry.getValue();
+                if (artifact.getBundleId() == bundleEvent.getBundle().getBundleId())
+                {
+                    log("Bundle " + bundleEvent.getBundle().getBundleId() + " has been uninstalled", null);
+                    currentManagedArtifacts.remove(entry.getKey());
+                    break;
+                }
+            }
+        }
+    }
+
     private void process(Set files)
     {
         List/*<ArtifactListener>*/ listeners = FileInstall.getListeners();
@@ -554,6 +575,7 @@
 
     public void close()
     {
+        this.context.removeBundleListener(this);
         interrupt();
         try
         {
diff --git a/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/DirectoryWatcherTest.java b/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/DirectoryWatcherTest.java
index 486c9ac..a17fcae 100644
--- a/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/DirectoryWatcherTest.java
+++ b/fileinstall/src/test/java/org/apache/felix/fileinstall/internal/DirectoryWatcherTest.java
@@ -28,9 +28,8 @@
 import org.easymock.MockControl;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleListener;
 import org.osgi.service.packageadmin.PackageAdmin;
-import org.apache.felix.fileinstall.internal.DirectoryWatcher;
-import org.apache.felix.fileinstall.internal.FileInstall;
 
 
 /**
@@ -64,6 +63,7 @@
 
     public void testGetLongWithNonExistentProperty()
     {
+        mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
         mockBundleContextControl.replay();
         dw = new DirectoryWatcher( props, mockBundleContext );
         assertEquals( "getLong gives the default value for non-existing properties", 100, dw.getLong( props, TEST, 100 ) );
@@ -73,6 +73,8 @@
     public void testGetLongWithExistentProperty()
     {
         props.put( TEST, "33" );
+
+        mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
         mockBundleContextControl.replay();
         dw = new DirectoryWatcher( props, mockBundleContext );
         assertEquals( "getLong retrieves the right property value", 33, dw.getLong( props, TEST, 100 ) );
@@ -83,6 +85,7 @@
     {
         props.put( TEST, "incorrect" );
 
+        mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
         mockBundleContext.getServiceReference( "org.osgi.service.log.LogService" );
         mockBundleContextControl.setReturnValue( null );
         mockBundleContextControl.replay();
@@ -93,6 +96,7 @@
 
     public void testGetBooleanWithNonExistentProperty()
     {
+        mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
         mockBundleContextControl.replay();
         dw = new DirectoryWatcher( props, mockBundleContext );
         assertEquals( "getBoolean gives the default value for non-existing properties", true, dw.getBoolean( props, TEST, true ) );
@@ -102,6 +106,8 @@
     public void testGetBooleanWithExistentProperty()
     {
         props.put( TEST, "true" );
+
+        mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
         mockBundleContextControl.replay();
         dw = new DirectoryWatcher( props, mockBundleContext );
         assertEquals( "getBoolean retrieves the right property value", true, dw.getBoolean( props, TEST, false ) );
@@ -112,6 +118,7 @@
     {
         props.put( TEST, "incorrect" );
 
+        mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
         mockBundleContext.getServiceReference( "org.osgi.service.log.LogService" );
         mockBundleContextControl.setReturnValue( null );
         mockBundleContextControl.replay();
@@ -122,6 +129,7 @@
 
     public void testGetFileWithNonExistentProperty()
     {
+        mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
         mockBundleContextControl.replay();
         dw = new DirectoryWatcher( props, mockBundleContext );
         assertEquals( "getFile gives the default value for non-existing properties", new File("tmp"), dw.getFile( props, TEST, new File("tmp") ) );
@@ -131,6 +139,8 @@
     public void testGetFileWithExistentProperty()
     {
         props.put( TEST, "test" );
+
+        mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
         mockBundleContextControl.replay();
         dw = new DirectoryWatcher( props, mockBundleContext );
         assertEquals( "getBoolean retrieves the right property value", new File("test"), dw.getFile( props, TEST, new File("tmp") ) );
@@ -145,6 +155,8 @@
         props.put( DirectoryWatcher.DIR, new File( "src/test/resources" ).getAbsolutePath() );
         props.put( DirectoryWatcher.TMPDIR, new File( "src/test/resources" ).getAbsolutePath() );
         props.put( DirectoryWatcher.FILTER, ".*\\.cfg" );
+
+        mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
         mockBundleContextControl.replay();
         dw = new DirectoryWatcher( props, mockBundleContext );
 
@@ -162,6 +174,8 @@
     public void testDefaultParametersAreSetAfterEmptyInitialization()
     {
         props.put( DirectoryWatcher.DIR, new File( "src/test/resources" ).getAbsolutePath() );
+
+        mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
         mockBundleContextControl.replay();
         dw = new DirectoryWatcher( props, mockBundleContext );
 
@@ -178,6 +192,7 @@
 
     public void testIsFragment() throws Exception
     {
+        mockBundleContext.addBundleListener((BundleListener) org.easymock.EasyMock.anyObject());
         mockBundleContext.createFilter( "" );
         mockBundleContextControl.setMatcher( MockControl.ALWAYS_MATCHER );
         mockBundleContextControl.setReturnValue( null );