FELIX-3039 Add new ds.delayed.keepInstances configuration property to prevent cleanup of unused delayed components.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1185082 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ScrConfiguration.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ScrConfiguration.java
index dec743a..a988a70 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ScrConfiguration.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ScrConfiguration.java
@@ -53,11 +53,15 @@
public class ScrConfiguration
{
- private static final String VALUE_TRUE = "true";
+ private static final String VALUE_TRUE = Boolean.TRUE.toString();
- static final String PROP_FACTORY_ENABLED = "ds.factory.enabled";
+ public static final String PID = "org.apache.felix.scr.ScrService";
- static final String PROP_LOGLEVEL = "ds.loglevel";
+ public static final String PROP_FACTORY_ENABLED = "ds.factory.enabled";
+
+ public static final String PROP_DELAYED_KEEP_INSTANCES = "ds.delayed.keepInstances";
+
+ public static final String PROP_LOGLEVEL = "ds.loglevel";
// framework property to enable the CT workarounds (see FELIX-2526)
private static final String PROP_CT_WORKAROUND = "ds.ctworkaround";
@@ -80,7 +84,7 @@
private boolean factoryEnabled;
- static final String PID = "org.apache.felix.scr.ScrService";
+ private boolean keepInstances;
public ScrConfiguration( BundleContext bundleContext )
{
@@ -105,11 +109,13 @@
{
logLevel = getDefaultLogLevel();
factoryEnabled = getDefaultFactoryEnabled();
+ keepInstances = getDefaultKeepInstances();
}
else
{
logLevel = getLogLevel( config.get( PROP_LOGLEVEL ) );
- factoryEnabled = VALUE_TRUE.equals( String.valueOf( config.get( PROP_FACTORY_ENABLED ) ) );
+ factoryEnabled = VALUE_TRUE.equalsIgnoreCase( String.valueOf( config.get( PROP_FACTORY_ENABLED ) ) );
+ keepInstances = VALUE_TRUE.equalsIgnoreCase( String.valueOf( config.get( PROP_DELAYED_KEEP_INSTANCES ) ) );
}
}
@@ -129,6 +135,12 @@
}
+ public boolean keepInstances()
+ {
+ return keepInstances;
+ }
+
+
public static boolean hasCtWorkaround( final BundleContext bundleContext )
{
boolean ctWorkaround = VALUE_TRUE.equals( bundleContext.getProperty( PROP_CT_WORKAROUND ) );
@@ -157,6 +169,12 @@
}
+ private boolean getDefaultKeepInstances()
+ {
+ return VALUE_TRUE.equals( bundleContext.getProperty( PROP_DELAYED_KEEP_INSTANCES ) );
+ }
+
+
private int getDefaultLogLevel()
{
return getLogLevel( bundleContext.getProperty( PROP_LOGLEVEL ) );
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java
index 64300d3..84e9480 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java
@@ -83,14 +83,24 @@
{ "4", "3", "2", "1" }));
adList
- .add(new AttributeDefinitionImpl(
- ScrConfiguration.PROP_FACTORY_ENABLED,
- "Extended Factory Components",
- "Whether or not to enable the support for creating Factory Component instances based on factory configuration."
- + " This is an Apache Felix SCR specific extension, explicitly not supported by the Declarative Services "
- + "specification. Reliance on this feature prevent the component from being used with other Declarative "
- + "Services implementations. The default value is false to disable this feature.", this
- .getScrConfiguration().isFactoryEnabled()));
+ .add(new AttributeDefinitionImpl(
+ ScrConfiguration.PROP_FACTORY_ENABLED,
+ "Extended Factory Components",
+ "Whether or not to enable the support for creating Factory Component instances based on factory configuration."
+ + " This is an Apache Felix SCR specific extension, explicitly not supported by the Declarative Services "
+ + "specification. Reliance on this feature prevent the component from being used with other Declarative "
+ + "Services implementations. The default value is false to disable this feature.", this
+ .getScrConfiguration().isFactoryEnabled()));
+
+ adList.add( new AttributeDefinitionImpl(
+ ScrConfiguration.PROP_DELAYED_KEEP_INSTANCES,
+ "Keep Component Instances",
+ "Whether or not to keep instances of delayed components once they are not referred to any more. The "
+ + "Declarative Services specifications suggests that instances of delayed components are disposed off "
+ + "if there is not used any longer. Setting this flag causes the components to not be disposed off "
+ + "and thus prevent them from being constantly recreated if often used. Examples of such components "
+ + "may be EventHandler services. The default is to dispose off unused components.", this
+ .getScrConfiguration().keepInstances() ) );
return new ObjectClassDefinition()
{
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 ba8a1a8..c8466d7 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
@@ -107,8 +107,9 @@
m_useCount--;
// unget the service instance if no bundle is using it
- // any longer
- if ( m_useCount == 0 )
+ // any longer unless delayed component instances have to
+ // be kept (FELIX-3039)
+ if ( m_useCount == 0 && !getActivator().getConfiguration().keepInstances() )
{
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 9f1c240..5c6b017 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
@@ -19,15 +19,21 @@
package org.apache.felix.scr.integration;
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
import junit.framework.TestCase;
import org.apache.felix.scr.Component;
+import org.apache.felix.scr.impl.config.ScrConfiguration;
import org.apache.felix.scr.integration.components.SimpleComponent;
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;
+import org.osgi.service.cm.Configuration;
@RunWith(JUnit4TestRunner.class)
@@ -170,4 +176,58 @@
TestCase.assertEquals( Component.STATE_REGISTERED, component.getState() );
TestCase.assertNull( SimpleComponent.INSTANCE );
}
+
+ @Test
+ public void test_DelayedSimpleComponent_service_keep_instance() throws IOException
+ {
+ // configure SCR to keep instances
+ Configuration scrConfig = getConfigurationAdmin().getConfiguration( ScrConfiguration.PID, null );
+ Dictionary props = scrConfig.getProperties();
+ if ( props == null )
+ {
+ props = new Hashtable();
+ }
+ props.put( ScrConfiguration.PROP_DELAYED_KEEP_INSTANCES, Boolean.TRUE.toString() );
+ scrConfig.update( props );
+ delay();
+
+ 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 );
+ }
+
+ // component instance must not be disposed off (due to config)
+ TestCase.assertEquals( Component.STATE_ACTIVE, component.getState() );
+ TestCase.assertNotNull( SimpleComponent.INSTANCE );
+
+ // delete the SCR configuration again
+ scrConfig.delete();
+ }
}