FELIX-1825 Deactivate component instances of delayed components which
are not referenced any more
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@830970 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
index 4f0c4d0..f10db78 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
@@ -777,6 +777,12 @@
}
+ void ungetService( DelayedComponentManager dcm )
+ {
+ log( dcm, "ungetService" );
+ }
+
+
void enable( AbstractComponentManager acm )
{
log( acm, "enable" );
@@ -1032,6 +1038,13 @@
{
return dcm.getInstance();
}
+
+
+ void ungetService( DelayedComponentManager dcm )
+ {
+ dcm.deleteComponent( ComponentConstants.DEACTIVATION_REASON_UNSPECIFIED );
+ dcm.changeState( Registered.getInstance() );
+ }
}
protected static final class Registered extends Satisfied
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/DelayedComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/DelayedComponentManager.java
index 58b5dfa..5a35abb 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/DelayedComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/DelayedComponentManager.java
@@ -19,6 +19,9 @@
package org.apache.felix.scr.impl.manager;
+import java.util.HashSet;
+import java.util.Set;
+
import org.apache.felix.scr.impl.BundleComponentActivator;
import org.apache.felix.scr.impl.config.ComponentHolder;
import org.apache.felix.scr.impl.metadata.ComponentMetadata;
@@ -33,6 +36,9 @@
public class DelayedComponentManager extends ImmediateComponentManager implements ServiceFactory
{
+ // keep the using bundles as reference "counters" for instance deactivation
+ private final Set usingBundles = new HashSet();
+
/**
* @param activator
* @param metadata
@@ -59,6 +65,9 @@
{
super.deleteComponent( reason );
}
+
+ // ensure the refence set is also clear
+ usingBundles.clear();
}
@@ -72,17 +81,23 @@
public synchronized Object getService( Bundle bundle, ServiceRegistration sr )
{
- return state().getService(this);
+ usingBundles.add(bundle);
+ return state().getService( this );
}
- protected boolean createRealComponent()
- {
- return super.createComponent();
- }
- public void ungetService( Bundle arg0, ServiceRegistration arg1, Object arg2 )
+ protected boolean createRealComponent()
{
- // nothing to do here
+ return super.createComponent();
}
+
+ public void ungetService( Bundle bundle, ServiceRegistration sr, Object service )
+ {
+ usingBundles.remove( bundle );
+ if ( usingBundles.isEmpty() )
+ {
+ state().ungetService( this );
+ }
+ }
}
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java
index c5393c0..9f1c240 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ServiceComponentTest.java
@@ -26,6 +26,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
@@ -84,4 +85,89 @@
&& !propKey.startsWith( "." ) );
}
}
+
+
+ @Test
+ public void test_DelayedSimpleComponent_service_single_use()
+ {
+ final String pid = "DelayedServiceComponent";
+
+ // one single component exists without configuration
+ final Component component = findComponentByName( pid );
+ TestCase.assertNotNull( component );
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+ component.enable();
+ delay();
+
+ // the delayed service is expected to only be registered before use
+ TestCase.assertEquals( Component.STATE_REGISTERED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ // get the service
+ ServiceReference reference = bundleContext.getServiceReference( "java.lang.Object" );
+ TestCase.assertNotNull( reference );
+ try
+ {
+ final Object theService = bundleContext.getService( reference );
+
+ // service must now be active
+ TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+
+ // and of course we expect the instance
+ TestCase.assertEquals( SimpleComponent.INSTANCE, theService );
+ }
+ finally
+ {
+ bundleContext.ungetService( reference );
+ }
+
+ // service is not used anymore, ensure REGISTERED state and INSTANCE==null
+ TestCase.assertEquals( Component.STATE_REGISTERED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+ }
+
+
+ @Test
+ public void test_DelayedSimpleComponent_service_multi_use()
+ {
+ final String pid = "DelayedServiceComponent";
+
+ // one single component exists without configuration
+ final Component component = findComponentByName( pid );
+ TestCase.assertNotNull( component );
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+
+ component.enable();
+ delay();
+
+ // the delayed service is expected to only be registered before use
+ TestCase.assertEquals( Component.STATE_REGISTERED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ // get the service once
+ final ServiceReference reference1 = bundleContext.getServiceReference( "java.lang.Object" );
+ TestCase.assertNotNull( reference1 );
+ bundleContext.getService( reference1 );
+ TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+ TestCase.assertNotNull( SimpleComponent.INSTANCE );
+
+ // get the service a second time
+ final BundleContext bundleContext2 = bundle.getBundleContext();
+ final ServiceReference reference2 = bundleContext2.getServiceReference( "java.lang.Object" );
+ TestCase.assertNotNull( reference2 );
+ bundleContext2.getService( reference2 );
+ TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+ TestCase.assertNotNull( SimpleComponent.INSTANCE );
+
+ // unget the service once -- must still be active !
+ bundleContext2.ungetService( reference2 );
+ TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+ TestCase.assertNotNull( SimpleComponent.INSTANCE );
+
+ // unget the service second time -- must be registered and null now
+ bundleContext.ungetService( reference1 );
+ TestCase.assertEquals( Component.STATE_REGISTERED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+ }
}
diff --git a/scr/src/test/resources/integration_test_simple_components.xml b/scr/src/test/resources/integration_test_simple_components.xml
index dcca586..25e5c36 100644
--- a/scr/src/test/resources/integration_test_simple_components.xml
+++ b/scr/src/test/resources/integration_test_simple_components.xml
@@ -58,7 +58,7 @@
<property name="service.pid" value="FactoryConfigurationComponent" />
</scr:component>
- <!-- component is a stupid service to verify non-use of private props -->
+ <!-- component is a simple service to verify non-use of private props -->
<scr:component name="ServiceComponent"
enabled="false" immediate="true"
configuration-policy="ignore" >
@@ -71,6 +71,17 @@
</service>
</scr:component>
+ <!-- component is a simple service to verify deactivation when not being used any longer -->
+ <scr:component name="DelayedServiceComponent"
+ enabled="false" immediate="false"
+ configuration-policy="ignore" >
+ <implementation class="org.apache.felix.scr.integration.components.SimpleComponent" />
+ <property name="service.pid" value="ServiceComponent" />
+ <service>
+ <provide interface="java.lang.Object" />
+ </service>
+ </scr:component>
+
<!-- Component Factory Instances -->
<scr:component name="factory.component"
enabled="false"