FELIX-3536 split up spec and non-spec Factory component behavior into separate classes. Run spec-compliant tests with only spec behavior configured. Determine satisfied state from class rather than switch statement
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1346660 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java b/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
index 8aadf20..06f79da 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
@@ -35,6 +35,7 @@
import org.apache.felix.scr.impl.config.ImmediateComponentHolder;
import org.apache.felix.scr.impl.manager.AbstractComponentManager;
import org.apache.felix.scr.impl.manager.ComponentFactoryImpl;
+import org.apache.felix.scr.impl.manager.ConfigurationComponentFactoryImpl;
import org.apache.felix.scr.impl.metadata.ComponentMetadata;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
@@ -69,7 +70,7 @@
* <p>
* The {@link #checkComponentName(String)} will first add an entry to this
* map being the name of the component to reserve the name. After setting up
- * the component, the {@link #registerComponent(String, ComponentHolder)}
+ * the component, the {@link #registerComponentHolder(String, ComponentHolder)}
* method replaces the value of the named entry with the actual
* {@link ComponentHolder}.
*
@@ -305,8 +306,8 @@
/**
* Checks whether the component name is "globally" unique or not. If it is
* unique, it is reserved until the actual component is registered with
- * {@link #registerComponent(String, AbstractComponentManager)} or until
- * it is unreserved by calling {@link #unregisterComponent(String)}.
+ * {@link #registerComponentHolder(String, ComponentHolder)} or until
+ * it is unreserved by calling {@link #unregisterComponentHolder(String)}.
* If a component with the same name has already been reserved or registered
* a ComponentException is thrown with a descriptive message.
*
@@ -501,7 +502,14 @@
// 112.2.4 SCR must register a Component Factory
// service on behalf ot the component
// as soon as the component factory is satisfied
- holder = new ComponentFactoryImpl(activator, metadata);
+ if ( !activator.getConfiguration().isFactoryEnabled() )
+ {
+ holder = new ComponentFactoryImpl(activator, metadata);
+ }
+ else
+ {
+ holder = new ConfigurationComponentFactoryImpl(activator, metadata);
+ }
}
else
{
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 524fb27..b553411 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
@@ -554,31 +554,7 @@
protected abstract Object getService();
- final State getSatisfiedState()
- {
- if ( m_componentMetadata.isFactory() )
- {
- if ( this instanceof ComponentFactoryImpl.ComponentFactoryConfiguredInstance )
- {
- return Active.getInstance();
- }
- else if ( this instanceof ComponentFactoryImpl.ComponentFactoryNewInstance )
- {
- return FactoryInstance.getInstance();
- }
-
- return Factory.getInstance();
- }
- else if ( m_componentMetadata.isImmediate() )
- {
- return Active.getInstance();
- }
- else
- {
- return Registered.getInstance();
- }
- }
-
+ abstract State getSatisfiedState();
/**
* Registers the service on behalf of the component.
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
index a80b2f0..e81ec7e 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
@@ -18,8 +18,8 @@
*/
package org.apache.felix.scr.impl.manager;
+import java.util.ArrayList;
import java.util.Dictionary;
-import java.util.HashMap;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.Iterator;
@@ -77,27 +77,11 @@
*/
private Dictionary m_configuration;
- /**
- * The map of components created from Configuration objects maps PID to
- * {@link ImmediateComponentManager} for configuration updating this map is
- * lazily created. This map is only used if the {@link #m_isConfigurationFactory}
- * field is <code>true</code>.
- */
- private Map m_configuredServices;
-
- /**
- * Whether this instance supports creating component instances for factory
- * configuration instances. This is backwards compatibility behaviour and
- * contradicts the specification (Section 112.7)
- */
- private final boolean m_isConfigurationFactory;
-
public ComponentFactoryImpl( BundleComponentActivator activator, ComponentMetadata metadata )
{
super( activator, metadata );
m_componentInstances = new IdentityHashMap();
- m_isConfigurationFactory = activator.getConfiguration().isFactoryEnabled();
m_configuration = new Hashtable();
}
@@ -107,7 +91,7 @@
*/
public ComponentInstance newInstance( Dictionary dictionary )
{
- final ImmediateComponentManager cm = createComponentManager( true );
+ final ImmediateComponentManager cm = createComponentManager();
ComponentInstance instance;
cm.obtainStateLock();
@@ -176,19 +160,9 @@
/**
* The component factory does not have a component to create.
- * <p>
- * But in the backwards compatible case any instances created for factory
- * configuration instances are to enabled as a consequence of activating
- * the component factory.
*/
protected boolean createComponent()
{
- ImmediateComponentManager[] cms = getComponentManagers( m_configuredServices );
- for ( int i = 0; i < cms.length; i++ )
- {
- cms[i].enable( false );
- }
-
return true;
}
@@ -202,11 +176,6 @@
*/
protected void deleteComponent( int reason )
{
- ImmediateComponentManager[] cms = getComponentManagers( m_configuredServices );
- for ( int i = 0; i < cms.length; i++ )
- {
- cms[i].disable();
- }
}
@@ -282,6 +251,11 @@
return this;
}
+ State getSatisfiedState()
+ {
+ return Factory.getInstance();
+ }
+
//---------- Component interface
@@ -303,25 +277,6 @@
// providing an empty configuration
m_configuration = new Hashtable();
}
- else if ( m_isConfigurationFactory )
- {
- Map configuredServices = m_configuredServices;
- if ( configuredServices != null )
- {
- ImmediateComponentManager cm;
- synchronized ( configuredServices )
- {
- cm = ( ImmediateComponentManager ) configuredServices.remove( pid );
- }
-
- if ( cm != null )
- {
- log( LogService.LOG_DEBUG, "Disposing component after configuration deletion", null );
-
- cm.dispose();
- }
- }
- }
else
{
// 112.7 Factory Configuration not allowed for factory component
@@ -336,63 +291,6 @@
{
m_configuration = configuration;
}
- else if ( m_isConfigurationFactory ) //non-spec backwards compatible
- {
- obtainStateLock();
- try
- {
- ImmediateComponentManager cm;
- Map configuredServices = m_configuredServices;
- if ( configuredServices != null )
- {
- cm = ( ImmediateComponentManager ) configuredServices.get( pid );
- }
- else
- {
- m_configuredServices = new HashMap();
- configuredServices = m_configuredServices;
- cm = null;
- }
-
- if ( cm == null )
- {
- // create a new instance with the current configuration
- cm = createComponentManager( false );
-
- // this should not call component reactivation because it is
- // not active yet
- cm.reconfigure( configuration );
-
- // enable asynchronously if components are already enabled
- if ( getState() == STATE_FACTORY )
- {
- cm.enable( false );
- }
-
- // keep a reference for future updates
- configuredServices.put( pid, cm );
-
- }
- else
- {
- // update the configuration as if called as ManagedService
- //TODO deadlock potential, we are holding our own state lock.
- cm.obtainStateLock();
- try
- {
- cm.reconfigure( configuration );
- }
- finally
- {
- cm.releaseStateLock();
- }
- }
- }
- finally
- {
- releaseStateLock();
- }
- }
else
{
// 112.7 Factory Configuration not allowed for factory component
@@ -403,21 +301,16 @@
public Component[] getComponents()
{
- ImmediateComponentManager[] instances = getComponentManagers( m_componentInstances );
- ImmediateComponentManager[] services = getComponentManagers( m_configuredServices );
- int size = instances.length + services.length;
+ List cms = getComponentList();
+ return (Component[]) cms.toArray( new Component[ cms.size() ] );
+ }
- if ( size > 0 )
- {
- Component[] result = new Component[size + 1];
- result[0] = this;
- System.arraycopy( instances, 0, result, 1, instances.length );
- System.arraycopy( services, 0, result, instances.length + 1, services.length );
- return result;
- }
-
- return new Component[]
- { this };
+ protected List getComponentList()
+ {
+ List cms = new ArrayList( );
+ cms.add( this );
+ getComponentManagers( m_componentInstances, cms );
+ return cms;
}
@@ -449,10 +342,11 @@
*/
public void disposeComponents( int reason )
{
- ImmediateComponentManager[] cms = getComponentManagers( m_componentInstances );
- for ( int i = 0; i < cms.length; i++ )
+ List cms = new ArrayList( );
+ getComponentManagers( m_componentInstances, cms );
+ for ( Iterator i = cms.iterator(); i.hasNext(); )
{
- cms[i].dispose( reason );
+ ((AbstractComponentManager)i.next()).dispose( reason );
}
synchronized ( m_componentInstances )
@@ -460,14 +354,6 @@
m_componentInstances.clear();
}
- cms = getComponentManagers( m_configuredServices );
- for ( int i = 0; i < cms.length; i++ )
- {
- cms[i].dispose( reason );
- }
-
- m_configuredServices = null;
-
// finally dispose the component factory itself
dispose( reason );
}
@@ -491,30 +377,21 @@
* instance. The component manager is kept in the internal set of created
* components. The component is neither configured nor enabled.
*/
- private ImmediateComponentManager createComponentManager( final boolean newInstance )
+ private ImmediateComponentManager createComponentManager()
{
- if ( newInstance )
- {
- return new ComponentFactoryNewInstance( getActivator(), this, getComponentMetadata() );
- }
-
- return new ComponentFactoryConfiguredInstance( getActivator(), this, getComponentMetadata() );
+ return new ComponentFactoryNewInstance( getActivator(), this, getComponentMetadata() );
}
- private ImmediateComponentManager[] getComponentManagers( Map componentMap )
+ protected void getComponentManagers( Map componentMap, List componentManagers )
{
if ( componentMap != null )
{
synchronized ( componentMap )
{
- ImmediateComponentManager[] cm = new ImmediateComponentManager[componentMap.size()];
- componentMap.values().toArray( cm );
- return cm;
+ componentManagers.addAll( componentMap.values() );
}
}
-
- return new ImmediateComponentManager[0];
}
static class ComponentFactoryNewInstance extends ImmediateComponentManager {
@@ -525,15 +402,11 @@
super( activator, componentHolder, metadata );
}
- }
-
- static class ComponentFactoryConfiguredInstance extends ImmediateComponentManager {
-
- public ComponentFactoryConfiguredInstance( BundleComponentActivator activator, ComponentHolder componentHolder,
- ComponentMetadata metadata )
+ State getSatisfiedState()
{
- super( activator, componentHolder, metadata );
+ return FactoryInstance.getInstance();
}
}
+
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java
new file mode 100644
index 0000000..118a8e0
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ConfigurationComponentFactoryImpl.java
@@ -0,0 +1,256 @@
+/*
+ * 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.scr.impl.manager;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.scr.Component;
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.config.ComponentHolder;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+import org.osgi.service.log.LogService;
+
+/**
+ * The <code>ComponentFactoryImpl</code> extends the {@link org.apache.felix.scr.impl.manager.AbstractComponentManager}
+ * class to implement the component factory functionality. As such the
+ * OSGi Declarative Services <code>ComponentFactory</code> interface is
+ * implemented.
+ * <p>
+ * In addition the {@link org.apache.felix.scr.impl.config.ComponentHolder} interface is implemented to use this
+ * class directly as the holder for component instances created by the
+ * {@link #newInstance(java.util.Dictionary)} method.
+ * <p>
+ * Finally, if the <code>ds.factory.enabled</code> bundle context property is
+ * set to <code>true</code>, component instances can be created by factory
+ * configurations. This functionality is present for backwards compatibility
+ * with earlier releases of the Apache Felix Declarative Services implementation.
+ * But keep in mind, that this is non-standard behaviour.
+ */
+public class ConfigurationComponentFactoryImpl extends ComponentFactoryImpl implements ComponentHolder
+{
+
+ /**
+ * The map of components created from Configuration objects maps PID to
+ * {@link org.apache.felix.scr.impl.manager.ImmediateComponentManager} for configuration updating this map is
+ * lazily created.
+ */
+ private Map m_configuredServices;
+
+ public ConfigurationComponentFactoryImpl( BundleComponentActivator activator, ComponentMetadata metadata )
+ {
+ super( activator, metadata );
+ }
+
+
+ /**
+ * The component factory does not have a component to create.
+ * <p>
+ * But in the backwards compatible case any instances created for factory
+ * configuration instances are to enabled as a consequence of activating
+ * the component factory.
+ */
+ protected boolean createComponent()
+ {
+ List cms = new ArrayList( );
+ getComponentManagers( m_configuredServices, cms );
+ for ( Iterator i = cms.iterator(); i.hasNext(); )
+ {
+ ((AbstractComponentManager)i.next()).enable( false );
+ }
+
+ return true;
+ }
+
+
+ /**
+ * The component factory does not have a component to delete.
+ * <p>
+ * But in the backwards compatible case any instances created for factory
+ * configuration instances are to disabled as a consequence of deactivating
+ * the component factory.
+ */
+ protected void deleteComponent( int reason )
+ {
+ List cms = new ArrayList( );
+ getComponentManagers( m_configuredServices, cms );
+ for ( Iterator i = cms.iterator(); i.hasNext(); )
+ {
+ ((AbstractComponentManager)i.next()).disable();
+ }
+ }
+
+
+ //---------- ComponentHolder interface
+
+ public void configurationDeleted( String pid )
+ {
+ if ( pid.equals( getComponentMetadata().getConfigurationPid() ) )
+ {
+ super.configurationDeleted( pid );
+ }
+ else
+ {
+ Map configuredServices = m_configuredServices;
+ if ( configuredServices != null )
+ {
+ ImmediateComponentManager cm;
+ synchronized ( configuredServices )
+ {
+ cm = ( ImmediateComponentManager ) configuredServices.remove( pid );
+ }
+
+ if ( cm != null )
+ {
+ log( LogService.LOG_DEBUG, "Disposing component after configuration deletion", null );
+
+ cm.dispose();
+ }
+ }
+ }
+ }
+
+
+ public void configurationUpdated( String pid, Dictionary configuration )
+ {
+ if ( pid.equals( getComponentMetadata().getConfigurationPid() ) )
+ {
+ super.configurationUpdated( pid, configuration );
+ }
+ else //non-spec backwards compatible
+ {
+ obtainStateLock();
+ try
+ {
+ ImmediateComponentManager cm;
+ Map configuredServices = m_configuredServices;
+ if ( configuredServices != null )
+ {
+ cm = ( ImmediateComponentManager ) configuredServices.get( pid );
+ }
+ else
+ {
+ m_configuredServices = new HashMap();
+ configuredServices = m_configuredServices;
+ cm = null;
+ }
+
+ if ( cm == null )
+ {
+ // create a new instance with the current configuration
+ cm = createConfigurationComponentManager();
+
+ // this should not call component reactivation because it is
+ // not active yet
+ cm.reconfigure( configuration );
+
+ // enable asynchronously if components are already enabled
+ if ( getState() == STATE_FACTORY )
+ {
+ cm.enable( false );
+ }
+
+ // keep a reference for future updates
+ configuredServices.put( pid, cm );
+
+ }
+ else
+ {
+ // update the configuration as if called as ManagedService
+ //TODO deadlock potential, we are holding our own state lock.
+ cm.obtainStateLock();
+ try
+ {
+ cm.reconfigure( configuration );
+ }
+ finally
+ {
+ cm.releaseStateLock();
+ }
+ }
+ }
+ finally
+ {
+ releaseStateLock();
+ }
+ }
+ }
+
+
+ public Component[] getComponents()
+ {
+ List cms = getComponentList();
+ getComponentManagers( m_configuredServices, cms );
+ return (Component[]) cms.toArray( new Component[ cms.size() ] );
+ }
+
+
+ /**
+ * Disposes off all components ever created by this component holder. This
+ * method is called if either the Declarative Services runtime is stopping
+ * or if the owning bundle is stopped. In both cases all components created
+ * by this holder must be disposed off.
+ */
+ public void disposeComponents( int reason )
+ {
+ super.disposeComponents( reason );
+
+ List cms = new ArrayList( );
+ getComponentManagers( m_configuredServices, cms );
+ for ( Iterator i = cms.iterator(); i.hasNext(); )
+ {
+ ((AbstractComponentManager)i.next()).dispose( reason );
+ }
+
+ m_configuredServices = null;
+
+ // finally dispose the component factory itself
+ dispose( reason );
+ }
+
+
+
+ //---------- internal
+
+
+ /**
+ * Creates an {@link org.apache.felix.scr.impl.manager.ImmediateComponentManager} instance with the
+ * {@link org.apache.felix.scr.impl.BundleComponentActivator} and {@link org.apache.felix.scr.impl.metadata.ComponentMetadata} of this
+ * instance. The component manager is kept in the internal set of created
+ * components. The component is neither configured nor enabled.
+ */
+ private ImmediateComponentManager createConfigurationComponentManager()
+ {
+ return new ComponentFactoryConfiguredInstance( getActivator(), this, getComponentMetadata() );
+ }
+
+ static class ComponentFactoryConfiguredInstance extends ImmediateComponentManager {
+
+ public ComponentFactoryConfiguredInstance( BundleComponentActivator activator, ComponentHolder componentHolder,
+ ComponentMetadata metadata )
+ {
+ super( activator, componentHolder, metadata );
+ }
+
+ }
+}
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 8953ae3..f8c70bf 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
@@ -75,6 +75,10 @@
return this;
}
+ State getSatisfiedState()
+ {
+ return Registered.getInstance();
+ }
//---------- ServiceFactory interface -------------------------------------
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
index 6b8eac7..bf77da3 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
@@ -289,6 +289,10 @@
return m_implementationObject;
}
+ State getSatisfiedState()
+ {
+ return Active.getInstance();
+ }
protected void setFactoryProperties( Dictionary dictionary )
{
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentFactoryTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentFactoryTest.java
index f6a6980..8ad0b8e 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentFactoryTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentFactoryTest.java
@@ -328,168 +328,6 @@
TestCase.assertFalse( instanceMap.containsValue( instanceManager ) );
}
- @Test
- public void test_component_factory_with_factory_configuration() throws InvalidSyntaxException, IOException
- {
- // this test is about non-standard behaviour of ComponentFactory services
-
- final String componentname = "factory.component";
- final String componentfactory = "factory.component.factory";
-
- final Component component = findComponentByName( componentname );
-
- TestCase.assertNotNull( component );
- TestCase.assertFalse( component.isDefaultEnabled() );
-
- TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
- TestCase.assertNull( SimpleComponent.INSTANCE );
-
- component.enable();
- delay();
-
- TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
- TestCase.assertNull( SimpleComponent.INSTANCE );
-
- final ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "("
- + ComponentConstants.COMPONENT_FACTORY + "=" + componentfactory + ")" );
- TestCase.assertNotNull( refs );
- TestCase.assertEquals( 1, refs.length );
- final ComponentFactory factory = ( ComponentFactory ) bundleContext.getService( refs[0] );
- TestCase.assertNotNull( factory );
-
- final String factoryConfigPid = createFactoryConfiguration( componentname );
- delay();
-
- TestCase.assertNotNull( SimpleComponent.INSTANCE );
- TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
-
- final Map<?, ?> instanceMap = ( Map<?, ?> ) getFieldValue( component, "m_configuredServices" );
- TestCase.assertNotNull( instanceMap );
- TestCase.assertEquals( 1, instanceMap.size() );
-
- final Object instanceManager = getFieldValue( SimpleComponent.INSTANCE.m_activateContext.getComponentInstance(), "m_componentManager" );
- TestCase.assertTrue( instanceMap.containsValue( instanceManager ) );
-
-
- // check registered components
- Component[] allFactoryComponents = findComponentsByName( componentname );
- TestCase.assertNotNull( allFactoryComponents );
- TestCase.assertEquals( 2, allFactoryComponents.length );
- for ( int i = 0; i < allFactoryComponents.length; i++ )
- {
- final Component c = allFactoryComponents[i];
- if ( c.getId() == component.getId() )
- {
- TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
- }
- else if ( c.getId() == SimpleComponent.INSTANCE.m_id )
- {
- TestCase.assertEquals( Component.STATE_ACTIVE, c.getState() );
- }
- else
- {
- TestCase.fail( "Unexpected Component " + c );
- }
- }
-
- // modify the configuration
- Configuration config = getConfigurationAdmin().getConfiguration( factoryConfigPid );
- Dictionary props = config.getProperties();
- props.put( PROP_NAME, PROP_NAME_FACTORY );
- config.update( props );
- delay();
-
- // ensure instance with new configuration
- TestCase.assertNotNull( SimpleComponent.INSTANCE );
- TestCase.assertEquals( PROP_NAME_FACTORY, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
-
- // check registered components
- allFactoryComponents = findComponentsByName( componentname );
- TestCase.assertNotNull( allFactoryComponents );
- TestCase.assertEquals( 2, allFactoryComponents.length );
- for ( int i = 0; i < allFactoryComponents.length; i++ )
- {
- final Component c = allFactoryComponents[i];
- if ( c.getId() == component.getId() )
- {
- TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
- }
- else if ( c.getId() == SimpleComponent.INSTANCE.m_id )
- {
- TestCase.assertEquals( Component.STATE_ACTIVE, c.getState() );
- }
- else
- {
- TestCase.fail( "Unexpected Component " + c );
- }
- }
-
- // disable the factory
- component.disable();
- delay();
-
- // factory is disabled and so is the instance
- TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
- TestCase.assertNull( SimpleComponent.INSTANCE );
- TestCase.assertEquals( 1, instanceMap.size() );
-
- // enabled the factory
- component.enable();
- delay();
-
- // factory is enabled and so is the instance
- TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
- TestCase.assertNotNull( SimpleComponent.INSTANCE );
- TestCase.assertEquals( 1, instanceMap.size() );
-
- // check registered components
- allFactoryComponents = findComponentsByName( componentname );
- TestCase.assertNotNull( allFactoryComponents );
- TestCase.assertEquals( 2, allFactoryComponents.length );
- for ( int i = 0; i < allFactoryComponents.length; i++ )
- {
- final Component c = allFactoryComponents[i];
- if ( c.getId() == component.getId() )
- {
- TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
- }
- else if ( c.getId() == SimpleComponent.INSTANCE.m_id )
- {
- TestCase.assertEquals( Component.STATE_ACTIVE, c.getState() );
- }
- else
- {
- TestCase.fail( "Unexpected Component " + c );
- }
- }
-
- // delete the configuration
- getConfigurationAdmin().getConfiguration( factoryConfigPid ).delete();
- delay();
-
- // factory is enabled but instance has been removed
- TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
- TestCase.assertNull( SimpleComponent.INSTANCE );
- TestCase.assertEquals( 0, instanceMap.size() );
-
- // check registered components
- allFactoryComponents = findComponentsByName( componentname );
- TestCase.assertNotNull( allFactoryComponents );
- TestCase.assertEquals( 1, allFactoryComponents.length );
- for ( int i = 0; i < allFactoryComponents.length; i++ )
- {
- final Component c = allFactoryComponents[i];
- if ( c.getId() == component.getId() )
- {
- TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
- }
- else
- {
- TestCase.fail( "Unexpected Component " + c );
- }
- }
- }
-
@Test
public void test_component_factory_reference() throws InvalidSyntaxException
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
index c134fd7..d89b4fc 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
@@ -88,6 +88,8 @@
// the descriptor file to use for the installed test bundle
protected static String descriptorFile = "/integration_test_simple_components.xml";
+ protected static boolean NONSTANDARD_COMPONENT_FACTORY_BEHAVIOR = false;
+
static
{
theConfig = new Hashtable<String, String>();
@@ -120,7 +122,7 @@
mavenBundle( "org.apache.felix", "org.apache.felix.configadmin", "1.0.10" )
),
junitBundles(),
- systemProperty( "ds.factory.enabled" ).value( "true" )
+ systemProperty( "ds.factory.enabled" ).value( Boolean.toString( NONSTANDARD_COMPONENT_FACTORY_BEHAVIOR ) )
);
final Option vmOption = ( paxRunnerVmOption != null ) ? CoreOptions.vmOption( paxRunnerVmOption ) : null;
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ConfigurationComponentFactoryTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ConfigurationComponentFactoryTest.java
new file mode 100644
index 0000000..fb0e4d2
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ConfigurationComponentFactoryTest.java
@@ -0,0 +1,224 @@
+/*
+ * 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.scr.integration;
+
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+
+import junit.framework.TestCase;
+import org.apache.felix.scr.Component;
+import org.apache.felix.scr.integration.components.SimpleComponent;
+import org.apache.felix.scr.integration.components.SimpleServiceImpl;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.component.ComponentException;
+import org.osgi.service.component.ComponentFactory;
+import org.osgi.service.component.ComponentInstance;
+
+
+/**
+ * Tests of nonstandard ComponentFactory behavior
+ */
+
+@RunWith(JUnit4TestRunner.class)
+public class ConfigurationComponentFactoryTest extends ComponentTestBase
+{
+
+ private static final String PROP_NAME_FACTORY = ComponentTestBase.PROP_NAME + ".factory";
+
+ static
+ {
+ NONSTANDARD_COMPONENT_FACTORY_BEHAVIOR = true;
+ // uncomment to enable debugging of this test class
+ // paxRunnerVmOption = DEBUG_VM_OPTION;
+ }
+
+
+
+ @Test
+ public void test_component_factory_with_factory_configuration() throws InvalidSyntaxException, IOException
+ {
+ // this test is about non-standard behaviour of ComponentFactory services
+
+ final String componentname = "factory.component";
+ final String componentfactory = "factory.component.factory";
+
+ final Component component = findComponentByName( componentname );
+
+ TestCase.assertNotNull( component );
+ TestCase.assertFalse( component.isDefaultEnabled() );
+
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ component.enable();
+ delay();
+
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+
+ final ServiceReference[] refs = bundleContext.getServiceReferences( ComponentFactory.class.getName(), "("
+ + ComponentConstants.COMPONENT_FACTORY + "=" + componentfactory + ")" );
+ TestCase.assertNotNull( refs );
+ TestCase.assertEquals( 1, refs.length );
+ final ComponentFactory factory = ( ComponentFactory ) bundleContext.getService( refs[0] );
+ TestCase.assertNotNull( factory );
+
+ final String factoryConfigPid = createFactoryConfiguration( componentname );
+ delay();
+
+ TestCase.assertNotNull( SimpleComponent.INSTANCE );
+ TestCase.assertEquals( PROP_NAME, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
+
+ final Map<?, ?> instanceMap = ( Map<?, ?> ) getFieldValue( component, "m_configuredServices" );
+ TestCase.assertNotNull( instanceMap );
+ TestCase.assertEquals( 1, instanceMap.size() );
+
+ final Object instanceManager = getFieldValue( SimpleComponent.INSTANCE.m_activateContext.getComponentInstance(), "m_componentManager" );
+ TestCase.assertTrue( instanceMap.containsValue( instanceManager ) );
+
+
+ // check registered components
+ Component[] allFactoryComponents = findComponentsByName( componentname );
+ TestCase.assertNotNull( allFactoryComponents );
+ TestCase.assertEquals( 2, allFactoryComponents.length );
+ for ( int i = 0; i < allFactoryComponents.length; i++ )
+ {
+ final Component c = allFactoryComponents[i];
+ if ( c.getId() == component.getId() )
+ {
+ TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
+ }
+ else if ( c.getId() == SimpleComponent.INSTANCE.m_id )
+ {
+ TestCase.assertEquals( Component.STATE_ACTIVE, c.getState() );
+ }
+ else
+ {
+ TestCase.fail( "Unexpected Component " + c );
+ }
+ }
+
+ // modify the configuration
+ Configuration config = getConfigurationAdmin().getConfiguration( factoryConfigPid );
+ Dictionary props = config.getProperties();
+ props.put( PROP_NAME, PROP_NAME_FACTORY );
+ config.update( props );
+ delay();
+
+ // ensure instance with new configuration
+ TestCase.assertNotNull( SimpleComponent.INSTANCE );
+ TestCase.assertEquals( PROP_NAME_FACTORY, SimpleComponent.INSTANCE.getProperty( PROP_NAME ) );
+
+ // check registered components
+ allFactoryComponents = findComponentsByName( componentname );
+ TestCase.assertNotNull( allFactoryComponents );
+ TestCase.assertEquals( 2, allFactoryComponents.length );
+ for ( int i = 0; i < allFactoryComponents.length; i++ )
+ {
+ final Component c = allFactoryComponents[i];
+ if ( c.getId() == component.getId() )
+ {
+ TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
+ }
+ else if ( c.getId() == SimpleComponent.INSTANCE.m_id )
+ {
+ TestCase.assertEquals( Component.STATE_ACTIVE, c.getState() );
+ }
+ else
+ {
+ TestCase.fail( "Unexpected Component " + c );
+ }
+ }
+
+ // disable the factory
+ component.disable();
+ delay();
+
+ // factory is disabled and so is the instance
+ TestCase.assertEquals( Component.STATE_DISABLED, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+ TestCase.assertEquals( 1, instanceMap.size() );
+
+ // enabled the factory
+ component.enable();
+ delay();
+
+ // factory is enabled and so is the instance
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNotNull( SimpleComponent.INSTANCE );
+ TestCase.assertEquals( 1, instanceMap.size() );
+
+ // check registered components
+ allFactoryComponents = findComponentsByName( componentname );
+ TestCase.assertNotNull( allFactoryComponents );
+ TestCase.assertEquals( 2, allFactoryComponents.length );
+ for ( int i = 0; i < allFactoryComponents.length; i++ )
+ {
+ final Component c = allFactoryComponents[i];
+ if ( c.getId() == component.getId() )
+ {
+ TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
+ }
+ else if ( c.getId() == SimpleComponent.INSTANCE.m_id )
+ {
+ TestCase.assertEquals( Component.STATE_ACTIVE, c.getState() );
+ }
+ else
+ {
+ TestCase.fail( "Unexpected Component " + c );
+ }
+ }
+
+ // delete the configuration
+ getConfigurationAdmin().getConfiguration( factoryConfigPid ).delete();
+ delay();
+
+ // factory is enabled but instance has been removed
+ TestCase.assertEquals( Component.STATE_FACTORY, component.getState() );
+ TestCase.assertNull( SimpleComponent.INSTANCE );
+ TestCase.assertEquals( 0, instanceMap.size() );
+
+ // check registered components
+ allFactoryComponents = findComponentsByName( componentname );
+ TestCase.assertNotNull( allFactoryComponents );
+ TestCase.assertEquals( 1, allFactoryComponents.length );
+ for ( int i = 0; i < allFactoryComponents.length; i++ )
+ {
+ final Component c = allFactoryComponents[i];
+ if ( c.getId() == component.getId() )
+ {
+ TestCase.assertEquals( Component.STATE_FACTORY, c.getState() );
+ }
+ else
+ {
+ TestCase.fail( "Unexpected Component " + c );
+ }
+ }
+ }
+
+}