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 );
+            }
+        }
+    }
+
+}