FELIX-1488 Dynamic configuration bindings have to also be
persisted for this use case:
1. start managed service s1 of bundle b1
2. configuration is prodived and bound to b1
3. stop bundle b1
4. restart configuration admin service
==> configuration must still be bound to b1
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@804891 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/configadmin/src/test/java/org/apache/felix/cm/MockBundle.java b/configadmin/src/test/java/org/apache/felix/cm/MockBundle.java
new file mode 100644
index 0000000..d1ef4e7
--- /dev/null
+++ b/configadmin/src/test/java/org/apache/felix/cm/MockBundle.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.cm;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
+
+
+public class MockBundle implements Bundle
+{
+
+ private final BundleContext context;
+ private final String location;
+
+
+ public MockBundle( BundleContext context, String location )
+ {
+ this.context = context;
+ this.location = location;
+ }
+
+
+ public Enumeration findEntries( String arg0, String arg1, boolean arg2 )
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ public BundleContext getBundleContext()
+ {
+ return context;
+ }
+
+
+ public long getBundleId()
+ {
+ return 0;
+ }
+
+
+ public URL getEntry( String arg0 )
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ public Enumeration getEntryPaths( String arg0 )
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ public Dictionary getHeaders()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ public Dictionary getHeaders( String arg0 )
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ public long getLastModified()
+ {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+
+ public String getLocation()
+ {
+ return location;
+ }
+
+
+ public ServiceReference[] getRegisteredServices()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ public URL getResource( String arg0 )
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ public Enumeration getResources( String arg0 ) throws IOException
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ public ServiceReference[] getServicesInUse()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ public int getState()
+ {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+
+ public String getSymbolicName()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ public boolean hasPermission( Object arg0 )
+ {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+
+ public Class loadClass( String arg0 ) throws ClassNotFoundException
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+ public void start() throws BundleException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void stop() throws BundleException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void uninstall() throws BundleException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void update() throws BundleException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ public void update( InputStream arg0 ) throws BundleException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/configadmin/src/test/java/org/apache/felix/cm/MockBundleContext.java b/configadmin/src/test/java/org/apache/felix/cm/MockBundleContext.java
index c0aaae2..8cb6353 100644
--- a/configadmin/src/test/java/org/apache/felix/cm/MockBundleContext.java
+++ b/configadmin/src/test/java/org/apache/felix/cm/MockBundleContext.java
@@ -1,4 +1,4 @@
-/*
+/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
@@ -155,7 +155,7 @@
*/
public Bundle[] getBundles()
{
- return null;
+ return new Bundle[0];
}
diff --git a/configadmin/src/test/java/org/apache/felix/cm/impl/DynamicBindingsTest.java b/configadmin/src/test/java/org/apache/felix/cm/impl/DynamicBindingsTest.java
new file mode 100644
index 0000000..b3a3244
--- /dev/null
+++ b/configadmin/src/test/java/org/apache/felix/cm/impl/DynamicBindingsTest.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.cm.impl;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.Dictionary;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.cm.MockBundle;
+import org.apache.felix.cm.MockBundleContext;
+import org.apache.felix.cm.file.FilePersistenceManager;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+
+public class DynamicBindingsTest extends TestCase
+{
+
+ private File configLocation;
+
+ private File bindingsFile;
+
+ private FilePersistenceManager persistenceManager;
+
+ private static final String PID1 = "test.pid.1";
+
+ private static final String PID2 = "test.pid.2";
+
+ private static final String LOCATION1 = "test://location.1";
+
+ private static final String LOCATION2 = "test://location.2";
+
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ configLocation = new File( "target/config." + System.currentTimeMillis() );
+ persistenceManager = new FilePersistenceManager( configLocation.getAbsolutePath() );
+
+ bindingsFile = new File( configLocation, DynamicBindings.BINDINGS_FILE_NAME + ".config" );
+ }
+
+
+ protected void tearDown() throws Exception
+ {
+ bindingsFile.delete();
+ configLocation.delete();
+
+ super.tearDown();
+ }
+
+
+ public void test_no_bindings() throws IOException
+ {
+
+ // ensure there is no file
+ bindingsFile.delete();
+
+ final BundleContext ctx = new MockBundleContext();
+ final DynamicBindings dm = new DynamicBindings( ctx, persistenceManager );
+ final Dictionary bindings = getBindings( dm );
+
+ assertNotNull( bindings );
+ assertTrue( bindings.isEmpty() );
+ }
+
+
+ public void test_store_bindings() throws IOException
+ {
+ // ensure there is no file
+ bindingsFile.delete();
+
+ final BundleContext ctx = new MockBundleContext();
+ final DynamicBindings dm = new DynamicBindings( ctx, persistenceManager );
+
+ dm.putLocation( PID1, LOCATION1 );
+ assertEquals( LOCATION1, dm.getLocation( PID1 ) );
+
+ assertTrue( bindingsFile.exists() );
+
+ final Dictionary bindings = persistenceManager.load( DynamicBindings.BINDINGS_FILE_NAME );
+ assertNotNull( bindings );
+ assertEquals( 1, bindings.size() );
+ assertEquals( LOCATION1, bindings.get( PID1 ) );
+ }
+
+
+ public void test_store_and_load_bindings() throws IOException
+ {
+ // ensure there is no file
+ bindingsFile.delete();
+
+ // preset bindings
+ final DynamicBindings dm0 = new DynamicBindings( new MockBundleContext(), persistenceManager );
+ dm0.putLocation( PID1, LOCATION1 );
+
+ // check bindings
+ final BundleContext ctx = new DMTestMockBundleContext();
+ final DynamicBindings dm = new DynamicBindings( ctx, persistenceManager );
+
+ // API check
+ assertEquals( LOCATION1, dm.getLocation( PID1 ) );
+
+ // low level check
+ final Dictionary bindings = getBindings( dm );
+ assertNotNull( bindings );
+ assertEquals( 1, bindings.size() );
+ assertEquals( LOCATION1, bindings.get( PID1 ) );
+ }
+
+
+ public void test_store_and_load_bindings_with_cleanup() throws IOException
+ {
+ // ensure there is no file
+ bindingsFile.delete();
+
+ // preset bindings
+ final DynamicBindings dm0 = new DynamicBindings( new MockBundleContext(), persistenceManager );
+ dm0.putLocation( PID1, LOCATION1 );
+
+ // check bindings
+ final DynamicBindings dm = new DynamicBindings( new MockBundleContext(), persistenceManager );
+
+ // API check
+ assertNull( dm.getLocation( PID1 ) );
+
+ // low level check
+ final Dictionary bindings = getBindings( dm );
+ assertNotNull( bindings );
+ assertTrue( bindings.isEmpty() );
+ }
+
+
+ private static Dictionary getBindings( DynamicBindings dm )
+ {
+ try
+ {
+ final Field bindings = dm.getClass().getDeclaredField( "bindings" );
+ bindings.setAccessible( true );
+ return ( Dictionary ) bindings.get( dm );
+ }
+ catch ( Throwable t )
+ {
+ fail( "Cannot get bindings field: " + t );
+ return null;
+ }
+ }
+
+ private static class DMTestMockBundleContext extends MockBundleContext
+ {
+ public Bundle[] getBundles()
+ {
+ return new Bundle[]
+ { new MockBundle( this, LOCATION1 ) };
+ }
+ }
+}
diff --git a/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationTest.java b/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationTest.java
index ab77a1b..9eff377 100644
--- a/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationTest.java
+++ b/configadmin/src/test/java/org/apache/felix/cm/integration/ConfigurationTest.java
@@ -535,6 +535,95 @@
}
+ @Test
+ public void test_static_binding_and_unbinding() throws BundleException
+ {
+ final String pid = "test_static_binding_and_unbinding";
+ final String location = bundleContext.getBundle().getLocation();
+
+ // create and statically bind the configuration
+ configure( pid );
+ final Configuration config = getConfiguration( pid );
+ TestCase.assertEquals( pid, config.getPid() );
+ TestCase.assertNull( config.getBundleLocation() );
+
+ // bind the configuration
+ config.setBundleLocation( location );
+ TestCase.assertEquals( location, config.getBundleLocation() );
+
+ // restart CM bundle
+ final Bundle cmBundle = getCmBundle();
+ cmBundle.stop();
+ delay();
+ cmBundle.start();
+
+ // assert configuration still bound
+ final Configuration configAfterRestart = getConfiguration( pid );
+ TestCase.assertEquals( pid, configAfterRestart.getPid() );
+ TestCase.assertEquals( location, configAfterRestart.getBundleLocation() );
+
+ // unbind the configuration
+ configAfterRestart.setBundleLocation( null );
+ TestCase.assertNull( configAfterRestart.getBundleLocation() );
+
+ // restart CM bundle
+ cmBundle.stop();
+ delay();
+ cmBundle.start();
+
+ // assert configuration unbound
+ final Configuration configUnboundAfterRestart = getConfiguration( pid );
+ TestCase.assertEquals( pid, configUnboundAfterRestart.getPid() );
+ TestCase.assertNull( configUnboundAfterRestart.getBundleLocation() );
+ }
+
+
+ @Test
+ public void test_dynamic_binding_and_unbinding() throws BundleException
+ {
+ final String pid = "test_dynamic_binding_and_unbinding";
+
+ // create and statically bind the configuration
+ configure( pid );
+ final Configuration config = getConfiguration( pid );
+ TestCase.assertEquals( pid, config.getPid() );
+ TestCase.assertNull( config.getBundleLocation() );
+
+ // dynamically bind the configuration
+ bundle = installBundle( pid );
+ final String location = bundle.getLocation();
+ bundle.start();
+ delay();
+ TestCase.assertEquals( location, config.getBundleLocation() );
+
+ // restart CM bundle
+ final Bundle cmBundle = getCmBundle();
+ cmBundle.stop();
+ delay();
+ cmBundle.start();
+
+ // assert configuration still bound
+ final Configuration configAfterRestart = getConfiguration( pid );
+ TestCase.assertEquals( pid, configAfterRestart.getPid() );
+ TestCase.assertEquals( location, configAfterRestart.getBundleLocation() );
+
+ // stop bundle (configuration remains bound !!)
+ bundle.stop();
+ delay();
+ TestCase.assertEquals( location, configAfterRestart.getBundleLocation() );
+
+ // restart CM bundle
+ cmBundle.stop();
+ delay();
+ cmBundle.start();
+
+ // assert configuration still bound
+ final Configuration configBoundAfterRestart = getConfiguration( pid );
+ TestCase.assertEquals( pid, configBoundAfterRestart.getPid() );
+ TestCase.assertEquals( location, configBoundAfterRestart.getBundleLocation() );
+ }
+
+
/*
@Test
public void test_() throws BundleException