FELIX-3360 Fix dynamic configuration binding
- getConfiguration(pid) binds dynamically
- createConfiguration(pid) binds dynamically
- add integration tests to validate removal of
dynamic bindings
- make sure dynamic binding is cleared if
static binding is set
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1513740 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdminImpl.java b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdminImpl.java
index bf3df93..67efa2e 100644
--- a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdminImpl.java
+++ b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationAdminImpl.java
@@ -76,8 +76,9 @@
configurationManager.log( LogService.LOG_DEBUG, "createFactoryConfiguration(factoryPid={0})", new Object[]
{ factoryPid } );
- ConfigurationImpl config = configurationManager.createFactoryConfiguration( factoryPid, this.getBundle()
- .getLocation() );
+ // FELIX-3360: new factory configuration with implicit binding is dynamic
+ ConfigurationImpl config = configurationManager.createFactoryConfiguration( factoryPid, null );
+ config.setDynamicBundleLocation( this.getBundle().getLocation(), false );
return this.wrap( config );
}
@@ -114,7 +115,10 @@
ConfigurationImpl config = configurationManager.getConfiguration( pid );
if ( config == null )
{
- config = configurationManager.createConfiguration( pid, getBundle().getLocation() );
+ config = configurationManager.createConfiguration( pid, null );
+
+ // FELIX-3360: configuration creation with implicit binding is dynamic
+ config.setDynamicBundleLocation( getBundle().getLocation(), false );
}
else
{
@@ -125,7 +129,8 @@
{ config.getPid(), config.isNew() ? Boolean.TRUE : Boolean.FALSE,
this.getBundle().getLocation() } );
- config.setStaticBundleLocation( this.getBundle().getLocation() );
+ // FELIX-3360: first implicit binding is dynamic
+ config.setDynamicBundleLocation( getBundle().getLocation(), true );
}
else
{
diff --git a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java
index 51c3074..9ecde30 100644
--- a/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java
+++ b/configadmin/src/main/java/org/apache/felix/cm/impl/ConfigurationImpl.java
@@ -258,14 +258,10 @@
this.staticBundleLocation = bundleLocation;
storeSilently();
- // check whether the dynamic bundle location is different from the
- // static now. If so, the dynamic bundle location has to be
- // removed.
- if ( bundleLocation != null && getDynamicBundleLocation() != null
- && !bundleLocation.equals( getDynamicBundleLocation() ) )
- {
- setDynamicBundleLocation( null, false );
- }
+ // FELIX-3360: Always clear dynamic binding if a new static
+ // location is set. The static location is the relevant binding
+ // for a configuration unless it is not explicitly set.
+ setDynamicBundleLocation( null, false );
// CM 1.4
this.getConfigurationManager().locationChanged( this, oldBundleLocation );
@@ -295,7 +291,7 @@
* the case of this configuration to be dynamically bound a
* <code>CM_LOCATION_CHANGED</code> event is dispatched.
*/
- boolean tryBindLocation( final String bundleLocation )
+ void tryBindLocation( final String bundleLocation )
{
if ( this.getBundleLocation() == null )
{
@@ -303,8 +299,6 @@
{ getPidString(), bundleLocation } );
setDynamicBundleLocation( bundleLocation, true );
}
-
- return true;
}
diff --git a/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationBindingTest.java b/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationBindingTest.java
index a653d4b..eb39844 100644
--- a/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationBindingTest.java
+++ b/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationBindingTest.java
@@ -32,8 +32,10 @@
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.cm.ConfigurationEvent;
import org.osgi.service.cm.ConfigurationListener;
@@ -1003,6 +1005,127 @@
configListener.assertEvents( ConfigurationEvent.CM_LOCATION_CHANGED, 0 );
}
+ /**
+ * Tests configuration dynamic binding. See FELIX-3360.
+ */
+ @SuppressWarnings({ "serial", "javadoc" })
+ @Test
+ public void test_dynamic_binding_getConfiguration_pid() throws BundleException, IOException {
+ String ignoredPid = "test_dynamic_binding_getConfiguration_pid_ignored";
+ String pid1 = "test_dynamic_binding_getConfiguration_pid_1";
+ String pid2 = "test_dynamic_binding_getConfiguration_pid_2";
+
+ // ensure configuration is unbound
+ configure( pid1 );
+ delay();
+ configListener.assertEvents( ConfigurationEvent.CM_UPDATED, 1 );
+
+ bundle = installBundle( ignoredPid );
+ bundle.start();
+ delay();
+
+ // ensure config1 unbound
+ Configuration config1 = getConfiguration( pid1 );
+ TestCase.assertNull( config1.getBundleLocation() );
+
+ ServiceReference<ConfigurationAdmin> sr = bundle.getBundleContext().getServiceReference( ConfigurationAdmin.class );
+ ConfigurationAdmin bundleCa = bundle.getBundleContext().getService( sr );
+
+ // ensure dynamic binding
+ Configuration bundleConfig1 = bundleCa.getConfiguration( pid1 );
+ TestCase.assertEquals( bundle.getLocation(), bundleConfig1.getBundleLocation() );
+ delay();
+ configListener.assertEvents( ConfigurationEvent.CM_LOCATION_CHANGED, 1 );
+
+ // create config2; ensure dynamic binding
+ Configuration bundleConfig2 = bundleCa.getConfiguration( pid2 );
+ TestCase.assertNull(bundleConfig2.getProperties());
+ TestCase.assertEquals( bundle.getLocation(), bundleConfig2.getBundleLocation() );
+ bundleConfig2.update( new Hashtable<String, String>()
+ {
+ {
+ put( "key", "value" );
+ }
+ } );
+
+ // uninstall the bundle, 2 dynamic locations changed
+ bundle.uninstall();
+ bundle = null;
+ delay();
+ configListener.assertEvents( ConfigurationEvent.CM_LOCATION_CHANGED, 2 );
+
+ bundleConfig1 = getConfiguration( pid1 );
+ TestCase.assertNull( bundleConfig1.getBundleLocation() );
+
+ bundleConfig2 = getConfiguration( pid2 );
+ TestCase.assertNull(bundleConfig2.getBundleLocation());
+
+ bundleConfig1.delete();
+ bundleConfig2.delete();
+ }
+
+ /**
+ * Tests factory configuration dynamic binding. See FELIX-3360.
+ */
+ @SuppressWarnings({ "javadoc", "serial" })
+ @Test
+ public void test_dynamic_binding_createFactoryConfiguration_pid() throws BundleException, IOException {
+ String ignoredPid = "test_dynamic_binding_createFactoryConfiguration_pid_ignored";
+ String pid1 = null;
+ String pid2 = null;
+ String factoryPid1 = "test_dynamic_binding_createFactoryConfiguration_pid_1";
+ String factoryPid2 = "test_dynamic_binding_createFactoryConfiguration_pid_2";
+
+ // ensure configuration is unbound
+ pid1 = createFactoryConfiguration( factoryPid1 ).getPid();
+ delay();
+ configListener.assertEvents( ConfigurationEvent.CM_UPDATED, 1 );
+
+ bundle = installBundle( ignoredPid );
+ bundle.start();
+ delay();
+
+ // ensure config1 unbound
+ Configuration config1 = getConfiguration( pid1 );
+ TestCase.assertNull( config1.getBundleLocation() );
+
+ ServiceReference<ConfigurationAdmin> sr = bundle.getBundleContext().getServiceReference( ConfigurationAdmin.class );
+ ConfigurationAdmin bundleCa = bundle.getBundleContext().getService( sr );
+
+ // ensure dynamic binding
+ Configuration bundleConfig1 = bundleCa.getConfiguration( pid1 );
+ TestCase.assertEquals( bundle.getLocation(), bundleConfig1.getBundleLocation() );
+ delay();
+ configListener.assertEvents( ConfigurationEvent.CM_LOCATION_CHANGED, 1 );
+
+ // create config2; ensure dynamic binding
+ Configuration bundleConfig2 = bundleCa.createFactoryConfiguration( factoryPid2 );
+ pid2 = bundleConfig2.getPid();
+ TestCase.assertNull(bundleConfig2.getProperties());
+ TestCase.assertEquals( bundle.getLocation(), bundleConfig2.getBundleLocation() );
+ bundleConfig2.update( new Hashtable<String, String>()
+ {
+ {
+ put( "key", "value" );
+ }
+ } );
+
+ // uninstall the bundle, 2 dynamic locations changed
+ bundle.uninstall();
+ bundle = null;
+ delay();
+ configListener.assertEvents( ConfigurationEvent.CM_LOCATION_CHANGED, 2 );
+
+ bundleConfig1 = getConfiguration( pid1 );
+ TestCase.assertNull( bundleConfig1.getBundleLocation() );
+
+ bundleConfig2 = getConfiguration( pid2 );
+ TestCase.assertNull(bundleConfig2.getBundleLocation());
+
+ bundleConfig1.delete();
+ bundleConfig2.delete();
+ }
+
private static class ConfigListener implements ConfigurationListener {
private int[] events = new int[3];
@@ -1018,5 +1141,14 @@
TestCase.assertEquals( "Events of type " + type, numEvents, events[type - 1] );
events[type - 1] = 0;
}
+
+
+ void reset()
+ {
+ for ( int i = 0; i < events.length; i++ )
+ {
+ events[i] = 0;
+ }
+ }
}
}