FELIX-3200 Track ManagedService[Factory] PID changes
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1197348 13f79535-47bb-0310-9956-ffa450edef68
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 c9039b2..a3ea021 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
@@ -680,9 +680,13 @@
}
- private void configure( ServiceReference sr, ManagedService service )
+ /**
+ * Configures the ManagedService and returns the service.pid
+ * service property as a String[], which may be <code>null</code> if
+ * the ManagedService does not have such a property.
+ */
+ private void configure( String[] pids, ServiceReference sr, ManagedService service )
{
- String[] pids = getServicePid( sr );
if ( pids != null )
{
for ( int i = 0; i < pids.length; i++ )
@@ -696,9 +700,13 @@
}
- private void configure( ServiceReference sr, ManagedServiceFactory service )
+ /**
+ * Configures the ManagedServiceFactory and returns the service.pid
+ * service property as a String[], which may be <code>null</code> if
+ * the ManagedServiceFactory does not have such a property.
+ */
+ private void configure( String[] pids, ServiceReference sr, ManagedServiceFactory service )
{
- String[] pids = getServicePid( sr );
if ( pids != null )
{
for ( int i = 0; i < pids.length; i++ )
@@ -1227,7 +1235,6 @@
protected ManagedServiceFactoryHelper( ConfigurationImpl config )
{
super( config );
- // TODO Auto-generated constructor stub
}
@@ -1922,20 +1929,43 @@
public Object addingService( ServiceReference reference )
{
- Object serviceObject = super.addingService( reference );
+ Object service = super.addingService( reference );
// configure the managed service
- if ( serviceObject instanceof ManagedService )
+ final String[] pids;
+ if ( service instanceof ManagedService )
{
- cm.configure(reference, ( ManagedService ) serviceObject);
+ pids = getServicePid( reference );
+ cm.configure( pids, reference, ( ManagedService ) service );
}
else
{
cm.log( LogService.LOG_WARNING, "Service {0} is not a ManagedService", new Object[]
- { serviceObject } );
+ { service } );
+ pids = null;
}
- return serviceObject;
+ return new ManagedServiceHolder( service, pids );
+ }
+
+
+ public void modifiedService( ServiceReference reference, Object service )
+ {
+ ManagedServiceHolder holder = ( ManagedServiceHolder ) service;
+ String[] pids = getServicePid( reference );
+
+ if ( holder.isDifferentPids( pids ) )
+ {
+ cm.configure( pids, reference, ( ManagedService ) holder.getManagedService() );
+ holder.setConfiguredPids( pids );
+ }
+ }
+
+
+ public void removedService( ServiceReference reference, Object service )
+ {
+ final Object serviceObject = ( ( ManagedServiceHolder ) service ).getManagedService();
+ super.removedService( reference, serviceObject );
}
}
@@ -1957,19 +1987,94 @@
Object serviceObject = super.addingService( reference );
// configure the managed service factory
+ final String[] pids;
if ( serviceObject instanceof ManagedServiceFactory )
{
- cm.configure( reference, ( ManagedServiceFactory ) serviceObject );
+ pids = getServicePid( reference );
+ cm.configure( pids, reference, ( ManagedServiceFactory ) serviceObject );
}
else
{
cm.log( LogService.LOG_WARNING, "Service {0} is not a ManagedServiceFactory", new Object[]
{ serviceObject } );
+ pids = null;
}
- return serviceObject;
+ return new ManagedServiceHolder( serviceObject, pids );
+ }
+
+
+ public void modifiedService( ServiceReference reference, Object service )
+ {
+ ManagedServiceHolder holder = ( ManagedServiceHolder ) service;
+ String[] pids = getServicePid( reference );
+
+ if ( holder.isDifferentPids( pids ) )
+ {
+ cm.configure( pids, reference, ( ManagedServiceFactory ) holder.getManagedService() );
+ holder.setConfiguredPids( pids );
+ }
+
+ super.modifiedService( reference, service );
+ }
+
+
+ public void removedService( ServiceReference reference, Object service )
+ {
+ final Object serviceObject = ( ( ManagedServiceHolder ) service ).getManagedService();
+ super.removedService( reference, serviceObject );
}
}
+ private static class ManagedServiceHolder
+ {
+ private final Object managedService;
+ private String[] configuredPids;
+
+ ManagedServiceHolder( final Object managedService, final String[] configuredPids )
+ {
+ this.managedService = managedService;
+ this.configuredPids = configuredPids;
+ }
+
+
+ public Object getManagedService()
+ {
+ return managedService;
+ }
+
+
+ public void setConfiguredPids( String[] configuredPids )
+ {
+ this.configuredPids = configuredPids;
+ }
+
+
+ boolean isDifferentPids( final String[] pids )
+ {
+ if ( this.configuredPids == null && pids == null )
+ {
+ return false;
+ }
+ else if ( this.configuredPids == null )
+ {
+ return true;
+ }
+ else if ( pids == null )
+ {
+ return true;
+ }
+ else if ( this.configuredPids.length != pids.length )
+ {
+ return true;
+ }
+ else
+ {
+ HashSet thisPids = new HashSet( Arrays.asList( this.configuredPids ) );
+ HashSet otherPids = new HashSet( Arrays.asList( pids ) );
+ return !thisPids.equals( otherPids );
+ }
+ }
+ }
}
diff --git a/configadmin/src/test/java/org/apache/felix/cm/impl/ManagedServiceHolderTest.java b/configadmin/src/test/java/org/apache/felix/cm/impl/ManagedServiceHolderTest.java
new file mode 100644
index 0000000..8d0226e
--- /dev/null
+++ b/configadmin/src/test/java/org/apache/felix/cm/impl/ManagedServiceHolderTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import junit.framework.TestCase;
+
+
+public class ManagedServiceHolderTest extends TestCase
+{
+
+ private static final Constructor mshConstructor;
+ private static final Method msh_isDifferentPids;
+
+ static
+ {
+ try
+ {
+ Class clazz = Class.forName( "org.apache.felix.cm.impl.ConfigurationManager$ManagedServiceHolder" );
+ mshConstructor = clazz.getDeclaredConstructor( new Class[]
+ { Object.class, String[].class } );
+ mshConstructor.setAccessible( true );
+ msh_isDifferentPids = clazz.getDeclaredMethod( "isDifferentPids", new Class[]
+ { String[].class } );
+ msh_isDifferentPids.setAccessible( true );
+ }
+ catch ( Throwable t )
+ {
+ throw new RuntimeException( t );
+ }
+ }
+
+
+ public void test_isDifferentPids_null_null()
+ {
+ Object holder = createHolder( null );
+ assertFalse( "Expect both pids null to be the same", isDifferentPids( holder, null ) );
+ }
+
+
+ public void test_isDifferentPids_null_notNull()
+ {
+ Object holder = createHolder( null );
+ assertTrue( "Expect not same for one pid not null", isDifferentPids( holder, new String[]
+ { "entry" } ) );
+ }
+
+
+ public void test_isDifferentPids_notNull_null()
+ {
+ Object holder = createHolder( new String[]
+ { "entry" } );
+ assertTrue( "Expect not same for one pid not null", isDifferentPids( holder, null ) );
+ }
+
+
+ public void test_isDifferentPids_notNull_notNull()
+ {
+ final String[] pids10 =
+ { "a", "b" };
+ final String[] pids11 =
+ { "b", "a" };
+ final String[] pids20 =
+ { "a", "c" };
+ final String[] pids30 =
+ { "a", "b", "c" };
+
+ final Object holder10 = createHolder( pids10 );
+ assertFalse( isDifferentPids( holder10, pids10 ) );
+ assertFalse( isDifferentPids( holder10, pids11 ) );
+ assertTrue( isDifferentPids( holder10, pids20 ) );
+ assertTrue( isDifferentPids( holder10, pids30 ) );
+
+ final Object holder20 = createHolder( pids20 );
+ assertTrue( isDifferentPids( holder20, pids10 ) );
+ assertTrue( isDifferentPids( holder20, pids11 ) );
+ assertFalse( isDifferentPids( holder20, pids20 ) );
+ assertTrue( isDifferentPids( holder20, pids30 ) );
+ }
+
+
+ private Object createHolder( final String[] pids )
+ {
+ try
+ {
+ return mshConstructor.newInstance( new Object[]
+ { null, pids } );
+ }
+ catch ( Throwable t )
+ {
+ fail( t.getMessage() );
+ return null; // keep compiler quiet
+ }
+ }
+
+
+ private boolean isDifferentPids( final Object holder, final String[] pids )
+ {
+ try
+ {
+ Object result = msh_isDifferentPids.invoke( holder, new Object[]
+ { pids } );
+ return ( result instanceof Boolean ) && ( ( Boolean ) result ).booleanValue();
+ }
+ catch ( Throwable t )
+ {
+ fail( t.getMessage() );
+ return false; // keep compiler quiet
+ }
+ }
+}
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 9fb9c42..fe21d0a 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
@@ -383,4 +383,116 @@
final Configuration get2 = getConfigurationAdmin().getConfiguration( pid );
TestCase.assertEquals( bundle.getLocation(), get2.getBundleLocation() );
}
+
+ @Test
+ public void test_ManagedService_change_pid() throws BundleException, IOException
+ {
+ final String pid0 = "test_ManagedService_change_pid_0";
+ final String pid1 = "test_ManagedService_change_pid_1";
+
+ final Configuration config0 = configure( pid0, null, true );
+ final Configuration config1 = configure( pid1, null, true );
+ delay();
+
+ // register ManagedService ms1 with pid from said locationA
+ bundle = installBundle( pid0, ManagedServiceTestActivator.class );
+ bundle.start();
+ delay();
+
+ final ManagedServiceTestActivator tester = ManagedServiceTestActivator.INSTANCE;
+ TestCase.assertNotNull( tester.props );
+ TestCase.assertEquals( pid0, tester.props.get( Constants.SERVICE_PID ) );
+ TestCase.assertNull( tester.props.get( ConfigurationAdmin.SERVICE_FACTORYPID ) );
+ TestCase.assertNull( tester.props.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) );
+ TestCase.assertEquals( PROP_NAME, tester.props.get( PROP_NAME ) );
+ TestCase.assertEquals( 1, tester.numManagedServiceUpdatedCalls );
+
+ // change ManagedService PID
+ tester.changePid( pid1 );
+ delay();
+
+ TestCase.assertNotNull( tester.props );
+ TestCase.assertEquals( pid1, tester.props.get( Constants.SERVICE_PID ) );
+ TestCase.assertNull( tester.props.get( ConfigurationAdmin.SERVICE_FACTORYPID ) );
+ TestCase.assertNull( tester.props.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) );
+ TestCase.assertEquals( PROP_NAME, tester.props.get( PROP_NAME ) );
+ TestCase.assertEquals( 2, tester.numManagedServiceUpdatedCalls );
+
+ // delete
+ config0.delete();
+ config1.delete();
+ delay();
+
+ // ==> update with null
+ TestCase.assertNull( tester.props );
+ TestCase.assertEquals( 3, tester.numManagedServiceUpdatedCalls );
+ }
+
+
+ @Test
+ public void test_ManagedServiceFactory_change_pid() throws BundleException, IOException
+ {
+
+ final String factoryPid0 = "test_ManagedServiceFactory_change_pid_0";
+ final String factoryPid1 = "test_ManagedServiceFactory_change_pid_1";
+
+ final Configuration config0 = createFactoryConfiguration( factoryPid0, null, true );
+ final String pid0 = config0.getPid();
+ final Configuration config1 = createFactoryConfiguration( factoryPid1, null, true );
+ final String pid1 = config1.getPid();
+ delay();
+
+ bundle = installBundle( factoryPid0, ManagedServiceFactoryTestActivator.class );
+ bundle.start();
+ delay();
+
+ // pid0 properties provided on registration
+ final ManagedServiceFactoryTestActivator tester = ManagedServiceFactoryTestActivator.INSTANCE;
+ Dictionary<?, ?> props0 = tester.configs.get( pid0 );
+ TestCase.assertNotNull( props0 );
+ TestCase.assertEquals( pid0, props0.get( Constants.SERVICE_PID ) );
+ TestCase.assertEquals( factoryPid0, props0.get( ConfigurationAdmin.SERVICE_FACTORYPID ) );
+ TestCase.assertNull( props0.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) );
+ TestCase.assertEquals( PROP_NAME, props0.get( PROP_NAME ) );
+ TestCase.assertEquals( 0, tester.numManagedServiceUpdatedCalls );
+ TestCase.assertEquals( 1, tester.numManagedServiceFactoryUpdatedCalls );
+ TestCase.assertEquals( 0, tester.numManagedServiceFactoryDeleteCalls );
+
+ // change ManagedService PID
+ tester.changePid( factoryPid1 );
+ delay();
+
+ // pid1 properties must have been added
+ Dictionary<?, ?> props1 = tester.configs.get( pid1 );
+ TestCase.assertNotNull( props1 );
+ TestCase.assertEquals( pid1, props1.get( Constants.SERVICE_PID ) );
+ TestCase.assertEquals( factoryPid1, props1.get( ConfigurationAdmin.SERVICE_FACTORYPID ) );
+ TestCase.assertNull( props1.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) );
+ TestCase.assertEquals( PROP_NAME, props1.get( PROP_NAME ) );
+ TestCase.assertEquals( 0, tester.numManagedServiceUpdatedCalls );
+ TestCase.assertEquals( 2, tester.numManagedServiceFactoryUpdatedCalls );
+ TestCase.assertEquals( 0, tester.numManagedServiceFactoryDeleteCalls );
+
+ // pid0 properties must still exist !
+ Dictionary<?, ?> props01 = tester.configs.get( pid0 );
+ TestCase.assertNotNull( props01 );
+ TestCase.assertEquals( pid0, props01.get( Constants.SERVICE_PID ) );
+ TestCase.assertEquals( factoryPid0, props01.get( ConfigurationAdmin.SERVICE_FACTORYPID ) );
+ TestCase.assertNull( props01.get( ConfigurationAdmin.SERVICE_BUNDLELOCATION ) );
+ TestCase.assertEquals( PROP_NAME, props01.get( PROP_NAME ) );
+
+
+ // delete
+ config0.delete();
+ config1.delete();
+ delay();
+
+ // only pid1 properties removed because pid0 is not registered any longer
+ TestCase.assertNotNull( tester.configs.get( pid0 ) );
+ TestCase.assertNull( tester.configs.get( pid1 ) );
+ TestCase.assertEquals( 0, tester.numManagedServiceUpdatedCalls );
+ TestCase.assertEquals( 2, tester.numManagedServiceFactoryUpdatedCalls );
+ TestCase.assertEquals( 1, tester.numManagedServiceFactoryDeleteCalls );
+ }
+
}
diff --git a/configadmin/src/test/java/org/apache/felix/cm/integration/helper/ManagedServiceFactoryTestActivator.java b/configadmin/src/test/java/org/apache/felix/cm/integration/helper/ManagedServiceFactoryTestActivator.java
index 0301447..691ec44 100644
--- a/configadmin/src/test/java/org/apache/felix/cm/integration/helper/ManagedServiceFactoryTestActivator.java
+++ b/configadmin/src/test/java/org/apache/felix/cm/integration/helper/ManagedServiceFactoryTestActivator.java
@@ -19,7 +19,11 @@
package org.apache.felix.cm.integration.helper;
+import java.util.Dictionary;
+
+import org.ops4j.pax.swissbox.tinybundles.dp.Constants;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ManagedServiceFactory;
@@ -28,10 +32,15 @@
public static ManagedServiceFactoryTestActivator INSTANCE;
+ private Dictionary registrationProps;
+ private ServiceRegistration registration;
+
public void start( BundleContext context ) throws Exception
{
- context.registerService( ManagedServiceFactory.class.getName(), this, getServiceProperties( context ) );
+ this.registrationProps = getServiceProperties( context );
+ this.registration = context.registerService( ManagedServiceFactory.class.getName(), this,
+ this.registrationProps );
INSTANCE = this;
}
@@ -40,4 +49,11 @@
{
INSTANCE = null;
}
+
+
+ public void changePid( final String newPid )
+ {
+ this.registrationProps.put( Constants.SERVICE_PID, newPid );
+ this.registration.setProperties( this.registrationProps );
+ }
}
diff --git a/configadmin/src/test/java/org/apache/felix/cm/integration/helper/ManagedServiceTestActivator.java b/configadmin/src/test/java/org/apache/felix/cm/integration/helper/ManagedServiceTestActivator.java
index 0ed1261..db46b39 100644
--- a/configadmin/src/test/java/org/apache/felix/cm/integration/helper/ManagedServiceTestActivator.java
+++ b/configadmin/src/test/java/org/apache/felix/cm/integration/helper/ManagedServiceTestActivator.java
@@ -19,7 +19,11 @@
package org.apache.felix.cm.integration.helper;
+import java.util.Dictionary;
+
+import org.ops4j.pax.swissbox.tinybundles.dp.Constants;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ManagedService;
@@ -28,10 +32,13 @@
public static ManagedServiceTestActivator INSTANCE;
+ private Dictionary registrationProps;
+ private ServiceRegistration registration;
public void start( BundleContext context ) throws Exception
{
- context.registerService( ManagedService.class.getName(), this, getServiceProperties( context ) );
+ this.registrationProps = getServiceProperties( context );
+ this.registration = context.registerService( ManagedService.class.getName(), this, this.registrationProps );
INSTANCE = this;
}
@@ -40,4 +47,11 @@
{
INSTANCE = null;
}
+
+
+ public void changePid( final String newPid )
+ {
+ this.registrationProps.put( Constants.SERVICE_PID, newPid );
+ this.registration.setProperties( this.registrationProps );
+ }
}