You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by fm...@apache.org on 2009/08/19 11:39:21 UTC

svn commit: r805716 - in /felix/trunk/configadmin/src: main/java/org/apache/felix/cm/impl/ test/java/org/apache/felix/cm/impl/ test/java/org/apache/felix/cm/integration/

Author: fmeschbe
Date: Wed Aug 19 09:39:21 2009
New Revision: 805716

URL: http://svn.apache.org/viewvc?rev=805716&view=rev
Log:
FELIX-1488 configuration replacement if static bundle binding is
replaced as described in https://issues.apache.org/jira/browse/FELIX-1488?focusedCommentId=12744909&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12744909

Modified:
    felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationBase.java
    felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java
    felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
    felix/trunk/configadmin/src/test/java/org/apache/felix/cm/impl/MockConfigurationManager.java
    felix/trunk/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationBindingTest.java
    felix/trunk/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationTestBase.java

Modified: felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationBase.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationBase.java?rev=805716&r1=805715&r2=805716&view=diff
==============================================================================
--- felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationBase.java (original)
+++ felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationBase.java Wed Aug 19 09:39:21 2009
@@ -154,9 +154,26 @@
 
     void setStaticBundleLocation( final String bundleLocation )
     {
+        // FELIX-1488: If a configuration is bound to a location and a new
+        // location is statically set, the old binding must be removed
+        // by removing the configuration from the targets and the new binding
+        // must be setup by updating the configuration for new targets
+        boolean replace = ( this instanceof ConfigurationImpl ) && ( bundleLocation != null );
+        if ( replace && getDynamicBundleLocation() != null && !bundleLocation.equals( getDynamicBundleLocation() ) )
+        {
+            // remove configuration from current managed service [factory]
+            getConfigurationManager().deleted( ( ConfigurationImpl ) this, false );
+        }
+
         // 104.15.2.8 The bundle location will be set persistently
         this.staticBundleLocation = bundleLocation;
         storeSilently();
+
+        // check whether we have to assign the configuration to new targets
+        if ( replace )
+        {
+            getConfigurationManager().updated( ( ConfigurationImpl ) this, false );
+        }
     }
 
 

Modified: felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java?rev=805716&r1=805715&r2=805716&view=diff
==============================================================================
--- felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java (original)
+++ felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java Wed Aug 19 09:39:21 2009
@@ -123,7 +123,7 @@
     {
         this.isDeleted = true;
         getPersistenceManager().delete( this.getPid() );
-        getConfigurationManager().deleted( this );
+        getConfigurationManager().deleted( this, true );
     }
 
 
@@ -190,7 +190,7 @@
 
             configureFromPersistence( properties );
 
-            getConfigurationManager().updated( this );
+            getConfigurationManager().updated( this, true );
         }
     }
 
@@ -241,7 +241,7 @@
             // finally assign the configuration for use
             configure( newProperties );
 
-            getConfigurationManager().updated( this );
+            getConfigurationManager().updated( this, true );
         }
     }
 

Modified: felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java?rev=805716&r1=805715&r2=805716&view=diff
==============================================================================
--- felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java (original)
+++ felix/trunk/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationManager.java Wed Aug 19 09:39:21 2009
@@ -558,17 +558,17 @@
     }
 
 
-    void deleted( ConfigurationImpl config )
+    void deleted( ConfigurationImpl config, boolean fireEvent )
     {
         // remove the configuration from the cache
         removeConfiguration( config );
-        updateThread.schedule( new DeleteConfiguration( config ) );
+        updateThread.schedule( new DeleteConfiguration( config, fireEvent ) );
     }
 
 
-    void updated( ConfigurationImpl config )
+    void updated( ConfigurationImpl config, boolean fireEvent )
     {
-        updateThread.schedule( new UpdateConfiguration( config ) );
+        updateThread.schedule( new UpdateConfiguration( config, fireEvent ) );
     }
 
 
@@ -1276,14 +1276,15 @@
     {
 
         private final ConfigurationImpl config;
-
         private final Dictionary properties;
+        private final boolean fireEvent;
 
 
-        UpdateConfiguration( final ConfigurationImpl config )
+        UpdateConfiguration( final ConfigurationImpl config, boolean fireEvent )
         {
             this.config = config;
             this.properties = config.getProperties( true );
+            this.fireEvent = fireEvent;
         }
 
 
@@ -1299,7 +1300,8 @@
                     {
                         // find the primary configuration owner
                         final ServiceReference ownerRef = getOwner( config, srList );
-                        final String bundleLocation = ownerRef.getBundle().getLocation();
+                        final String bundleLocation = ( ownerRef != null ) ? ownerRef.getBundle().getLocation()
+                            : config.getBundleLocation();
 
                         // if the configuration is unbound, bind to owner
                         if ( config.getBundleLocation() == null )
@@ -1361,7 +1363,8 @@
                     {
                         // find the primary configuration owner
                         final ServiceReference ownerRef = getOwner( config, srList );
-                        final String bundleLocation = ownerRef.getBundle().getLocation();
+                        final String bundleLocation = ( ownerRef != null ) ? ownerRef.getBundle().getLocation()
+                            : config.getBundleLocation();
 
                         // if the configuration is unbound, bind to owner
                         if ( config.getBundleLocation() == null )
@@ -1437,7 +1440,10 @@
             {
                 // the update event has to be sent regardless of whether the
                 // configuration was updated in a managed service or not
-                fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPid(), config.getFactoryPid() );
+                if ( fireEvent )
+                {
+                    fireConfigurationEvent( ConfigurationEvent.CM_UPDATED, config.getPid(), config.getFactoryPid() );
+                }
             }
         }
 
@@ -1455,8 +1461,25 @@
                     }
                 }
             }
-
             // configuration has never been supplied or the binding is stale
+
+            // if the configuration is location bound, find a service reference
+            // from the same bundle
+            final String configLocation = config.getBundleLocation();
+            if (configLocation != null) {
+                for ( int i = 0; i < srList.length; i++ )
+                {
+                    if ( configLocation.equals(srList[i].getBundle().getLocation() ) )
+                    {
+                        return srList[i];
+                    }
+                }
+                // no service from the same bundle found, thus we cannot
+                // find a new owner !!
+                return null;
+            }
+            // configuration is not location bound (yet)
+
             // just use the first entry in the list as the new owner
             final ServiceReference ownerRef = srList[0];
             config.setServiceReference( ownerRef );
@@ -1476,16 +1499,19 @@
         private final String pid;
         private final String factoryPid;
         private final String configLocation;
+        private final boolean fireEvent;
 
 
-        DeleteConfiguration( ConfigurationImpl config )
+        DeleteConfiguration( ConfigurationImpl config, boolean fireEvent )
         {
             this.pid = config.getPid();
             this.factoryPid = config.getFactoryPid();
             this.configLocation = config.getBundleLocation();
+            this.fireEvent = fireEvent;
 
             // immediately unbind the configuration
             config.setDynamicBundleLocation( null );
+            config.setServiceReference( null );
         }
 
 
@@ -1571,7 +1597,10 @@
             {
                 // the delete event has to be sent regardless of whether the
                 // configuration was updated in a managed service or not
-                fireConfigurationEvent( ConfigurationEvent.CM_DELETED, pid, factoryPid );
+                if ( fireEvent )
+                {
+                    fireConfigurationEvent( ConfigurationEvent.CM_DELETED, pid, factoryPid );
+                }
             }
         }
 

Modified: felix/trunk/configadmin/src/test/java/org/apache/felix/cm/impl/MockConfigurationManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/test/java/org/apache/felix/cm/impl/MockConfigurationManager.java?rev=805716&r1=805715&r2=805716&view=diff
==============================================================================
--- felix/trunk/configadmin/src/test/java/org/apache/felix/cm/impl/MockConfigurationManager.java (original)
+++ felix/trunk/configadmin/src/test/java/org/apache/felix/cm/impl/MockConfigurationManager.java Wed Aug 19 09:39:21 2009
@@ -22,13 +22,13 @@
 public class MockConfigurationManager extends ConfigurationManager
 {
 
-    void updated( ConfigurationImpl config )
+    void updated( ConfigurationImpl config, boolean fireEvent )
     {
         // do nothing, might register the update call
     }
 
 
-    void deleted( ConfigurationImpl config )
+    void deleted( ConfigurationImpl config, boolean fireEvent )
     {
         // do nothing, might register the update call
     }

Modified: felix/trunk/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationBindingTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationBindingTest.java?rev=805716&r1=805715&r2=805716&view=diff
==============================================================================
--- felix/trunk/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationBindingTest.java (original)
+++ felix/trunk/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationBindingTest.java Wed Aug 19 09:39:21 2009
@@ -23,7 +23,10 @@
 import java.util.Hashtable;
 import junit.framework.TestCase;
 
+import org.apache.felix.cm.integration.helper.ManagedServiceFactoryTestActivator;
+import org.apache.felix.cm.integration.helper.ManagedServiceFactoryTestActivator2;
 import org.apache.felix.cm.integration.helper.ManagedServiceTestActivator;
+import org.apache.felix.cm.integration.helper.ManagedServiceTestActivator2;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.ops4j.pax.exam.junit.JUnit4TestRunner;
@@ -36,7 +39,7 @@
 public class ConfigurationBindingTest extends ConfigurationTestBase
 {
 
-    @Test
+     @Test
     public void test_configuration_unbound_on_uninstall() throws BundleException
     {
         String pid = "test.pid";
@@ -105,7 +108,7 @@
     }
 
 
-    @Test
+     @Test
     public void test_configuration_unbound_on_uninstall_with_cm_restart() throws BundleException
     {
         final String pid = "test.pid";
@@ -179,7 +182,7 @@
     }
 
 
-    @Test
+     @Test
     public void test_not_updated_new_configuration_not_bound_after_bundle_uninstall() throws IOException,
         BundleException
     {
@@ -220,7 +223,7 @@
     }
 
 
-    @Test
+     @Test
     public void test_create_with_location_unbind_before_service_supply() throws BundleException, IOException
     {
 
@@ -272,7 +275,7 @@
     }
 
 
-    @Test
+     @Test
     public void test_statically_bound() throws BundleException
     {
         final String pid = "test_statically_bound";
@@ -317,7 +320,7 @@
     }
 
 
-    @Test
+     @Test
     public void test_static_binding_and_unbinding() throws BundleException
     {
         final String pid = "test_static_binding_and_unbinding";
@@ -360,7 +363,7 @@
     }
 
 
-    @Test
+     @Test
     public void test_dynamic_binding_and_unbinding() throws BundleException
     {
         final String pid = "test_dynamic_binding_and_unbinding";
@@ -406,7 +409,7 @@
     }
 
 
-    @Test
+     @Test
     public void test_static_binding() throws BundleException
     {
         final String pid = "test_static_binding";
@@ -446,7 +449,7 @@
     }
 
 
-    @Test
+     @Test
     public void test_two_bundles_one_pid() throws BundleException, IOException
     {
         // 1. Bundle registers service with pid1
@@ -533,4 +536,198 @@
         TestCase.assertEquals( 1, tester21.numManagedServiceUpdatedCalls );
     }
 
+
+    @Test
+    public void test_switch_static_binding() throws BundleException
+    {
+        // 1. create config with pid and locationA
+        // 2. update config with properties
+        final String pid = "test_switch_static_binding";
+        final String locationA = "test:location/A/" + pid;
+        final Configuration config = configure( pid, locationA, true );
+
+        // 3. register ManagedService ms1 with pid from said locationA
+        final Bundle bundleA = installBundle( pid, ManagedServiceTestActivator.class, locationA );
+        bundleA.start();
+        delay();
+
+        // ==> configuration supplied to the service ms1
+        final ManagedServiceTestActivator testerA1 = ManagedServiceTestActivator.INSTANCE;
+        TestCase.assertNotNull( testerA1.props );
+        TestCase.assertEquals( 1, testerA1.numManagedServiceUpdatedCalls );
+
+        // 4. register ManagedService ms2 with pid from locationB
+        final String locationB = "test:location/B/" + pid;
+        final Bundle bundleB = installBundle( pid, ManagedServiceTestActivator2.class, locationB );
+        bundleB.start();
+        delay();
+
+        // ==> configuration not supplied to service ms2
+        final ManagedServiceTestActivator2 testerB1 = ManagedServiceTestActivator2.INSTANCE;
+        TestCase.assertNull( testerB1.props );
+        TestCase.assertEquals( 0, testerB1.numManagedServiceUpdatedCalls );
+
+        // 5. Call Configuration.setBundleLocation( "locationB" )
+        config.setBundleLocation( locationB );
+        delay();
+
+        // ==> configuration is bound to locationB
+        TestCase.assertEquals( locationB, config.getBundleLocation() );
+
+        // ==> configuration removed from service ms1
+        TestCase.assertNull( testerA1.props );
+        TestCase.assertEquals( 2, testerA1.numManagedServiceUpdatedCalls );
+
+        // ==> configuration supplied to the service ms2
+        TestCase.assertNotNull( testerB1.props );
+        TestCase.assertEquals( 1, testerB1.numManagedServiceUpdatedCalls );
+    }
+
+
+    @Test
+    public void test_switch_dynamic_binding() throws BundleException
+    {
+        // 1. create config with pid with null location
+        // 2. update config with properties
+        final String pid = "test_switch_dynamic_binding";
+        final String locationA = "test:location/A/" + pid;
+        final Configuration config = configure( pid, null, true );
+
+        // 3. register ManagedService ms1 with pid from locationA
+        final Bundle bundleA = installBundle( pid, ManagedServiceTestActivator.class, locationA );
+        bundleA.start();
+        delay();
+
+        // ==> configuration supplied to the service ms1
+        final ManagedServiceTestActivator testerA1 = ManagedServiceTestActivator.INSTANCE;
+        TestCase.assertNotNull( testerA1.props );
+        TestCase.assertEquals( 1, testerA1.numManagedServiceUpdatedCalls );
+
+        // ==> configuration is dynamically bound to locationA
+        TestCase.assertEquals( locationA, config.getBundleLocation() );
+
+        // 4. register ManagedService ms2 with pid from locationB
+        final String locationB = "test:location/B/" + pid;
+        final Bundle bundleB = installBundle( pid, ManagedServiceTestActivator2.class, locationB );
+        bundleB.start();
+        delay();
+
+        // ==> configuration not supplied to service ms2
+        final ManagedServiceTestActivator2 testerB1 = ManagedServiceTestActivator2.INSTANCE;
+        TestCase.assertNull( testerB1.props );
+        TestCase.assertEquals( 0, testerB1.numManagedServiceUpdatedCalls );
+
+        // 5. Call Configuration.setBundleLocation( "locationB" )
+        config.setBundleLocation( locationB );
+        delay();
+
+        // ==> configuration is bound to locationB
+        TestCase.assertEquals( locationB, config.getBundleLocation() );
+
+        // ==> configuration removed from service ms1
+        TestCase.assertNull( testerA1.props );
+        TestCase.assertEquals( 2, testerA1.numManagedServiceUpdatedCalls );
+
+        // ==> configuration supplied to the service ms2
+        TestCase.assertNotNull( testerB1.props );
+        TestCase.assertEquals( 1, testerB1.numManagedServiceUpdatedCalls );
+    }
+
+
+    @Test
+    public void test_switch_static_binding_factory() throws BundleException
+    {
+        // 1. create config with pid and locationA
+        // 2. update config with properties
+        final String factoryPid = "test_switch_static_binding_factory";
+        final String locationA = "test:location/A/" + factoryPid;
+        final Configuration config = createFactoryConfiguration( factoryPid, locationA, true );
+        final String pid = config.getPid();
+
+        // 3. register ManagedService ms1 with pid from said locationA
+        final Bundle bundleA = installBundle( factoryPid, ManagedServiceFactoryTestActivator.class, locationA );
+        bundleA.start();
+        delay();
+
+        // ==> configuration supplied to the service ms1
+        final ManagedServiceFactoryTestActivator testerA1 = ManagedServiceFactoryTestActivator.INSTANCE;
+        TestCase.assertNotNull( testerA1.configs.get( pid ) );
+        TestCase.assertEquals( 1, testerA1.numManagedServiceFactoryUpdatedCalls );
+
+        // 4. register ManagedService ms2 with pid from locationB
+        final String locationB = "test:location/B/" + factoryPid;
+        final Bundle bundleB = installBundle( factoryPid, ManagedServiceFactoryTestActivator2.class, locationB );
+        bundleB.start();
+        delay();
+
+        // ==> configuration not supplied to service ms2
+        final ManagedServiceFactoryTestActivator2 testerB1 = ManagedServiceFactoryTestActivator2.INSTANCE;
+        TestCase.assertNull( testerB1.configs.get( pid ));
+        TestCase.assertEquals( 0, testerB1.numManagedServiceFactoryUpdatedCalls );
+
+        // 5. Call Configuration.setBundleLocation( "locationB" )
+        config.setBundleLocation( locationB );
+        delay();
+
+        // ==> configuration is bound to locationB
+        TestCase.assertEquals( locationB, config.getBundleLocation() );
+
+        // ==> configuration removed from service ms1
+        TestCase.assertNull( testerA1.configs.get( pid ));
+        TestCase.assertEquals( 1, testerA1.numManagedServiceFactoryUpdatedCalls );
+        TestCase.assertEquals( 1, testerA1.numManagedServiceFactoryDeleteCalls );
+
+        // ==> configuration supplied to the service ms2
+        TestCase.assertNotNull( testerB1.configs.get( pid ) );
+        TestCase.assertEquals( 1, testerB1.numManagedServiceFactoryUpdatedCalls );
+    }
+
+
+    @Test
+    public void test_switch_dynamic_binding_factory() throws BundleException
+    {
+        // 1. create config with pid and locationA
+        // 2. update config with properties
+        final String factoryPid = "test_switch_static_binding_factory";
+        final String locationA = "test:location/A/" + factoryPid;
+        final Configuration config = createFactoryConfiguration( factoryPid, null, true );
+        final String pid = config.getPid();
+
+        // 3. register ManagedService ms1 with pid from said locationA
+        final Bundle bundleA = installBundle( factoryPid, ManagedServiceFactoryTestActivator.class, locationA );
+        bundleA.start();
+        delay();
+
+        // ==> configuration supplied to the service ms1
+        final ManagedServiceFactoryTestActivator testerA1 = ManagedServiceFactoryTestActivator.INSTANCE;
+        TestCase.assertNotNull( testerA1.configs.get( pid ) );
+        TestCase.assertEquals( 1, testerA1.numManagedServiceFactoryUpdatedCalls );
+
+        // 4. register ManagedService ms2 with pid from locationB
+        final String locationB = "test:location/B/" + factoryPid;
+        final Bundle bundleB = installBundle( factoryPid, ManagedServiceFactoryTestActivator2.class, locationB );
+        bundleB.start();
+        delay();
+
+        // ==> configuration not supplied to service ms2
+        final ManagedServiceFactoryTestActivator2 testerB1 = ManagedServiceFactoryTestActivator2.INSTANCE;
+        TestCase.assertNull( testerB1.configs.get( pid ));
+        TestCase.assertEquals( 0, testerB1.numManagedServiceFactoryUpdatedCalls );
+
+        // 5. Call Configuration.setBundleLocation( "locationB" )
+        config.setBundleLocation( locationB );
+        delay();
+
+        // ==> configuration is bound to locationB
+        TestCase.assertEquals( locationB, config.getBundleLocation() );
+
+        // ==> configuration removed from service ms1
+        TestCase.assertNull( testerA1.configs.get( pid ));
+        TestCase.assertEquals( 1, testerA1.numManagedServiceFactoryUpdatedCalls );
+        TestCase.assertEquals( 1, testerA1.numManagedServiceFactoryDeleteCalls );
+
+        // ==> configuration supplied to the service ms2
+        TestCase.assertNotNull( testerB1.configs.get( pid ) );
+        TestCase.assertEquals( 1, testerB1.numManagedServiceFactoryUpdatedCalls );
+    }
 }

Modified: felix/trunk/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationTestBase.java
URL: http://svn.apache.org/viewvc/felix/trunk/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationTestBase.java?rev=805716&r1=805715&r2=805716&view=diff
==============================================================================
--- felix/trunk/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationTestBase.java (original)
+++ felix/trunk/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationTestBase.java Wed Aug 19 09:39:21 2009
@@ -110,6 +110,13 @@
 
     protected Bundle installBundle( final String pid, final Class<?> activatorClass ) throws BundleException
     {
+        return installBundle( pid, activatorClass, activatorClass.getName() );
+    }
+
+
+    protected Bundle installBundle( final String pid, final Class<?> activatorClass, final String location )
+        throws BundleException
+    {
         final String activatorClassName = activatorClass.getName();
         final InputStream bundleStream = new MyTinyBundle().prepare(
             withBnd().set( Constants.BUNDLE_SYMBOLICNAME, activatorClassName ).set( Constants.BUNDLE_VERSION, "0.0.11" )
@@ -119,7 +126,7 @@
 
         try
         {
-            return bundleContext.installBundle( "test:" + activatorClassName, bundleStream );
+            return bundleContext.installBundle( location, bundleStream );
         }
         finally
         {