FELIX-3327 Throw IllegalStateException on setBundleLocation, getBundleLocation, update, and delete if the Configuration Admin Service has been stopped.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1238185 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdapter.java b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdapter.java
index b6cbade..2a3d2c3 100644
--- a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdapter.java
+++ b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdapter.java
@@ -75,6 +75,7 @@
         final String bundleLocation = delegatee.getBundleLocation();
         delegatee.getConfigurationManager().log( LogService.LOG_DEBUG, "getBundleLocation() ==> {0}", new Object[]
             { bundleLocation } );
+        checkActive();
         configurationAdmin.checkPermission( ( bundleLocation == null ) ? "*" : bundleLocation );
         checkDeleted();
         return bundleLocation;
@@ -92,6 +93,7 @@
                 { bundleLocation } );
 
         // CM 1.4 / 104.13.2.4
+        checkActive();
         final String configLocation = delegatee.getBundleLocation();
         configurationAdmin.checkPermission( ( configLocation == null ) ? "*" : configLocation );
         configurationAdmin.checkPermission( ( bundleLocation == null ) ? "*" : bundleLocation );
@@ -108,6 +110,7 @@
     {
         delegatee.getConfigurationManager().log( LogService.LOG_DEBUG, "update()", ( Throwable ) null );
 
+        checkActive();
         checkDeleted();
         delegatee.update();
     }
@@ -123,6 +126,7 @@
         delegatee.getConfigurationManager().log( LogService.LOG_DEBUG, "update(properties={0})", new Object[]
             { properties } );
 
+        checkActive();
         checkDeleted();
         delegatee.update( properties );
     }
@@ -151,6 +155,7 @@
     {
         delegatee.getConfigurationManager().log( LogService.LOG_DEBUG, "delete()", ( Throwable ) null );
 
+        checkActive();
         checkDeleted();
         delegatee.delete();
     }
@@ -184,6 +189,19 @@
     }
 
     /**
+     * Checks whether this configuration object is backed by an active
+     * Configuration Admin Service (ConfigurationManager here).
+     *
+     * @throws IllegalStateException If this configuration object is not
+     *      backed by an active ConfigurationManager
+     */
+    private void checkActive() {
+        if (!delegatee.isActive()) {
+            throw new IllegalStateException( "Configuration " + delegatee.getPid() + " not backed by an active Configuration Admin Service" );
+        }
+    }
+
+    /**
      * Checks whether this configuration object has already been deleted.
      *
      * @throws IllegalStateException If this configuration object has been
diff --git a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationBase.java b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationBase.java
index 37831db..6891060 100644
--- a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationBase.java
+++ b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationBase.java
@@ -77,6 +77,16 @@
     }
 
 
+    /**
+     * Returns <code>true</code> if the ConfigurationManager of this
+     * configuration is still active.
+     */
+    boolean isActive()
+    {
+        return configurationManager.isActive();
+    }
+
+
     abstract void store() throws IOException;
 
 
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 f441a27..18bd4b4 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
@@ -161,6 +161,9 @@
     // flag indicating whether BundleChange events should be consumed (FELIX-979)
     private volatile boolean handleBundleEvents;
 
+    // flag indicating whether the manager is considered alive
+    private volatile boolean isActive;
+
     public void start( BundleContext bundleContext )
     {
         // track the log service using a ServiceTracker
@@ -231,6 +234,10 @@
         persistenceManagerTracker = new ServiceTracker( bundleContext, PersistenceManager.class.getName(), null );
         persistenceManagerTracker.open();
 
+        // consider alive now (before clients use Configuration Admin
+        // service registered in the next step)
+        isActive = true;
+
         // create and register configuration admin - start after PM tracker ...
         ConfigurationAdminFactory caf = new ConfigurationAdminFactory( this );
         Hashtable props = new Hashtable();
@@ -277,6 +284,10 @@
             reg.unregister();
         }
 
+        // consider inactive after unregistering such that during
+        // unregistration the manager is still alive and can react
+        isActive = false;
+
         // stop handling ManagedService[Factory] services
         managedServiceFactoryTracker.close();
         managedServiceTracker.close();
@@ -313,6 +324,15 @@
     }
 
 
+    /**
+     * Returns <code>true</code> if this manager is considered active.
+     */
+    boolean isActive()
+    {
+        return isActive;
+    }
+
+
     // ---------- Configuration caching support --------------------------------
 
     ConfigurationImpl getCachedConfiguration( String pid )
diff --git a/configadmin/src/test/java/org/apache/felix/cm/impl/ConfigurationAdapterTest.java b/configadmin/src/test/java/org/apache/felix/cm/impl/ConfigurationAdapterTest.java
index 5d5bb99..c95ca1c 100644
--- a/configadmin/src/test/java/org/apache/felix/cm/impl/ConfigurationAdapterTest.java
+++ b/configadmin/src/test/java/org/apache/felix/cm/impl/ConfigurationAdapterTest.java
@@ -51,7 +51,13 @@
     private static final String TEST_LOCATION = "test:location";
 
     private final PersistenceManager pm = new MockPersistenceManager();
-    private final MockConfigurationManager configMgr = new MockConfigurationManager();
+    private final MockConfigurationManager configMgr = new MockConfigurationManager()
+    {
+        boolean isActive()
+        {
+            return true;
+        }
+    };
 
     {
         ARRAY_VALUE = new String[]
diff --git a/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationBaseTest.java b/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationBaseTest.java
index fe21d0a..d8c661b 100644
--- a/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationBaseTest.java
+++ b/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationBaseTest.java
@@ -21,6 +21,7 @@
 
 import java.io.IOException;
 import java.util.Dictionary;
+import java.util.Hashtable;
 
 import junit.framework.TestCase;
 
@@ -46,6 +47,343 @@
         // paxRunnerVmOption = DEBUG_VM_OPTION;
     }
 
+
+    @Test
+    public void test_configuration_getFacotryPid_after_config_admin_stop() throws BundleException
+    {
+        final String pid = "test_configuration_after_config_admin_stop";
+        final Configuration config = configure( pid, null, true );
+
+        final Bundle cfgAdminBundle = configAdminTracker.getServiceReference().getBundle();
+        cfgAdminBundle.stop();
+        try
+        {
+            config.getFactoryPid();
+        }
+        finally
+        {
+            try
+            {
+                cfgAdminBundle.start();
+            }
+            catch ( BundleException be )
+            {
+                // tooo bad
+            }
+        }
+    }
+
+
+    @Test
+    public void test_configuration_equals_after_config_admin_stop() throws BundleException
+    {
+        final String pid = "test_configuration_after_config_admin_stop";
+        final Configuration config = configure( pid, null, true );
+
+        final Bundle cfgAdminBundle = configAdminTracker.getServiceReference().getBundle();
+        cfgAdminBundle.stop();
+        try
+        {
+            config.equals( config );
+        }
+        finally
+        {
+            try
+            {
+                cfgAdminBundle.start();
+            }
+            catch ( BundleException be )
+            {
+                // tooo bad
+            }
+        }
+    }
+
+
+    @Test
+    public void test_configuration_hashCode_after_config_admin_stop() throws BundleException
+    {
+        final String pid = "test_configuration_after_config_admin_stop";
+        final Configuration config = configure( pid, null, true );
+
+        final Bundle cfgAdminBundle = configAdminTracker.getServiceReference().getBundle();
+        cfgAdminBundle.stop();
+        try
+        {
+            config.hashCode();
+        }
+        finally
+        {
+            try
+            {
+                cfgAdminBundle.start();
+            }
+            catch ( BundleException be )
+            {
+                // tooo bad
+            }
+        }
+    }
+
+
+    @Test
+    public void test_configuration_toString_after_config_admin_stop() throws BundleException
+    {
+        final String pid = "test_configuration_after_config_admin_stop";
+        final Configuration config = configure( pid, null, true );
+
+        final Bundle cfgAdminBundle = configAdminTracker.getServiceReference().getBundle();
+        cfgAdminBundle.stop();
+        try
+        {
+            config.toString();
+        }
+        finally
+        {
+            try
+            {
+                cfgAdminBundle.start();
+            }
+            catch ( BundleException be )
+            {
+                // tooo bad
+            }
+        }
+    }
+
+
+    public void test_configuration_getPid_after_config_admin_stop() throws BundleException
+    {
+        final String pid = "test_configuration_after_config_admin_stop";
+        final Configuration config = configure( pid, null, true );
+
+        final Bundle cfgAdminBundle = configAdminTracker.getServiceReference().getBundle();
+        cfgAdminBundle.stop();
+        try
+        {
+            config.getPid();
+        }
+        finally
+        {
+            try
+            {
+                cfgAdminBundle.start();
+            }
+            catch ( BundleException be )
+            {
+                // tooo bad
+            }
+        }
+    }
+
+
+    @Test
+    public void test_configuration_after_getProperties_config_admin_stop() throws BundleException
+    {
+        final String pid = "test_configuration_after_config_admin_stop";
+        final Configuration config = configure( pid, null, true );
+
+        final Bundle cfgAdminBundle = configAdminTracker.getServiceReference().getBundle();
+        cfgAdminBundle.stop();
+        try
+        {
+            config.getProperties();
+        }
+        finally
+        {
+            try
+            {
+                cfgAdminBundle.start();
+            }
+            catch ( BundleException be )
+            {
+                // tooo bad
+            }
+        }
+    }
+
+
+    @Test
+    public void test_configuration_delete_after_config_admin_stop() throws BundleException
+    {
+        final String pid = "test_configuration_after_config_admin_stop";
+        final Configuration config = configure( pid, null, true );
+
+        final Bundle cfgAdminBundle = configAdminTracker.getServiceReference().getBundle();
+        cfgAdminBundle.stop();
+        try
+        {
+            config.delete();
+            TestCase.fail( "Expected IllegalStateException for config.delete" );
+        }
+        catch ( IllegalStateException ise )
+        {
+            // expected
+        }
+        catch ( Exception e )
+        {
+            TestCase.fail( "Expected IllegalStateException for config.delete" );
+        }
+        finally
+        {
+            try
+            {
+                cfgAdminBundle.start();
+            }
+            catch ( BundleException be )
+            {
+                // tooo bad
+            }
+        }
+    }
+
+
+    @Test
+    public void test_configuration_after_getBundleLocation_config_admin_stop() throws BundleException
+    {
+        final String pid = "test_configuration_after_config_admin_stop";
+        final Configuration config = configure( pid, null, true );
+
+        final Bundle cfgAdminBundle = configAdminTracker.getServiceReference().getBundle();
+        cfgAdminBundle.stop();
+        try
+        {
+            config.getBundleLocation();
+            TestCase.fail( "Expected IllegalStateException for config.getBundleLocation" );
+        }
+        catch ( IllegalStateException ise )
+        {
+            // expected
+        }
+        catch ( Exception e )
+        {
+            TestCase.fail( "Expected IllegalStateException for config.getBundleLocation" );
+        }
+        finally
+        {
+            try
+            {
+                cfgAdminBundle.start();
+            }
+            catch ( BundleException be )
+            {
+                // tooo bad
+            }
+        }
+    }
+
+
+    @Test
+    public void test_configuration_setBundleLocation_after_config_admin_stop() throws BundleException
+    {
+        final String pid = "test_configuration_after_config_admin_stop";
+        final Configuration config = configure( pid, null, true );
+
+        final Bundle cfgAdminBundle = configAdminTracker.getServiceReference().getBundle();
+        cfgAdminBundle.stop();
+        try
+        {
+            config.setBundleLocation( "?*" );
+            TestCase.fail( "Expected IllegalStateException for config.setBundleLocation" );
+        }
+        catch ( IllegalStateException ise )
+        {
+            // expected
+        }
+        catch ( Exception e )
+        {
+            TestCase.fail( "Expected IllegalStateException for config.setBundleLocation" );
+        }
+        finally
+        {
+            try
+            {
+                cfgAdminBundle.start();
+            }
+            catch ( BundleException be )
+            {
+                // tooo bad
+            }
+        }
+    }
+
+
+    @Test
+    public void test_configuration_update_after_config_admin_stop() throws BundleException
+    {
+        final String pid = "test_configuration_after_config_admin_stop";
+        final Configuration config = configure( pid, null, true );
+
+        final Bundle cfgAdminBundle = configAdminTracker.getServiceReference().getBundle();
+        cfgAdminBundle.stop();
+        try
+        {
+            config.update();
+            TestCase.fail( "Expected IllegalStateException for config.update" );
+        }
+        catch ( IllegalStateException ise )
+        {
+            // expected
+        }
+        catch ( Exception e )
+        {
+            TestCase.fail( "Expected IllegalStateException for config.update" );
+        }
+        finally
+        {
+            try
+            {
+                cfgAdminBundle.start();
+            }
+            catch ( BundleException be )
+            {
+                // tooo bad
+            }
+        }
+    }
+
+
+    @SuppressWarnings("serial")
+    @Test
+    public void test_configuration_update_with_Dictionary_after_config_admin_stop() throws BundleException
+    {
+        final String pid = "test_configuration_after_config_admin_stop";
+        final Configuration config = configure( pid, null, true );
+
+        final Bundle cfgAdminBundle = configAdminTracker.getServiceReference().getBundle();
+        cfgAdminBundle.stop();
+        try
+        {
+            config.update( new Hashtable<String, Object>()
+            {
+                {
+                    put( "sample", "sample" );
+                }
+            } );
+            TestCase.fail( "Expected IllegalStateException for config.update" );
+        }
+        catch ( IllegalStateException ise )
+        {
+            // expected
+        }
+        catch ( Exception e )
+        {
+            TestCase.fail( "Expected IllegalStateException for config.update" );
+        }
+        finally
+        {
+            try
+            {
+                cfgAdminBundle.start();
+            }
+            catch ( BundleException be )
+            {
+                // tooo bad
+            }
+        }
+    }
+
+
     @Test
     public void test_basic_configuration_configure_then_start() throws BundleException, IOException
     {