FELIX-2578 Refactor SCR configuration setup to support late wiring of Configuration Admin API
Refactored configuration admin support into a support class and
unified component handling again. If Configuration Admin is there
the support class provides configuration, otherwise the support
class is not instantiated and components are not provided with
additional configuration.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1067145 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/pom.xml b/scr/pom.xml
index a5ee3c6..f076b0a 100644
--- a/scr/pom.xml
+++ b/scr/pom.xml
@@ -219,18 +219,6 @@
                             org.osgi.service.packageadmin;version="[1.2,2)";resolution:=optional,
                             
                             <!--
-                                Configuration Admin version 1.2 (from R4.0) is enough
-                                (FELIX-2578: API is currently required)  
-                            -->
-                            org.osgi.service.cm;version="[1.2,2)",
-                            
-                            <!--
-                                Metatype is optional and if it is
-                                present, version 1.1 (from R4.1) is enough  
-                            -->
-                            org.osgi.service.metatype;version="[1.1,2)";resolution:=optional,
-
-                            <!--
                                 SCR API is required (we also export it) and must
                                 be of any 1.1 version, because we implement that
                                 exact version. This import is only used if the
@@ -239,6 +227,18 @@
                             -->
                             org.osgi.service.component;version="[1.1,1.2)"
                         </Import-Package>
+                        <DynamicImport-Package>
+                            <!--
+                                Configuration Admin version 1.2 (from R4.0) is enough
+                            -->
+                            org.osgi.service.cm;version="[1.2,2)",
+                            
+                            <!--
+                                Metatype is optional and if it is
+                                present, version 1.1 (from R4.1) is enough  
+                            -->
+                            org.osgi.service.metatype;version="[1.1,2)"
+                        </DynamicImport-Package>
                         <Embed-Dependency>
                             kxml2
                         </Embed-Dependency>
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/Activator.java b/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
index 32bce7a..267f7dc 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
@@ -23,7 +23,6 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.felix.scr.impl.config.ConfigurationComponentRegistry;
 import org.apache.felix.scr.impl.config.ScrConfiguration;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
@@ -94,7 +93,7 @@
 
         // prepare component registry
         m_componentBundles = new HashMap();
-        m_componentRegistry = createComponentRegistry( context);
+        m_componentRegistry = new ComponentRegistry( context );
 
         // get the configuration
         m_configuration = new ScrConfiguration( context );
@@ -368,22 +367,6 @@
     }
 
 
-    public static ComponentRegistry createComponentRegistry( BundleContext bundleContext )
-    {
-        try
-        {
-            return new ConfigurationComponentRegistry( bundleContext );
-        }
-        catch ( Throwable t )
-        {
-            log( LogService.LOG_INFO, bundleContext.getBundle(),
-                "ConfigurationAdmin supporting ComponentRegistry not available, not using ConfigurationAdmin", t );
-        }
-
-        return new ComponentRegistry( bundleContext );
-    }
-
-
     /**
      * Method to actually emit the log message. If the LogService is available,
      * the message will be logged through the LogService. Otherwise the message
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 685f7c6..36bd41f 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
@@ -28,13 +28,18 @@
 import org.apache.felix.scr.Component;
 import org.apache.felix.scr.ScrService;
 import org.apache.felix.scr.impl.config.ComponentHolder;
-import org.apache.felix.scr.impl.config.UnconfiguredComponentHolder;
+import org.apache.felix.scr.impl.config.ConfigurationSupport;
+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.metadata.ComponentMetadata;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.ComponentException;
 
@@ -45,9 +50,15 @@
  * registers itself as the {@link ScrService} to support access to the
  * registered components.
  */
-public class ComponentRegistry implements ScrService
+public class ComponentRegistry implements ScrService, ServiceListener
 {
 
+    // the name of the ConfigurationAdmin service
+    public static final String CONFIGURATION_ADMIN = "org.osgi.service.cm.ConfigurationAdmin";
+
+    // the bundle context
+    private BundleContext m_bundleContext;
+
     /**
      * The map of known components indexed by component name. The values are
      * either the component names (for name reservations) or implementations
@@ -88,13 +99,27 @@
      */
     private ServiceRegistration m_registration;
 
+    // ConfigurationAdmin support -- created on demand upon availability of
+    // the ConfigurationAdmin service
+    private ConfigurationSupport configurationSupport;
 
     protected ComponentRegistry( BundleContext context )
     {
+        m_bundleContext = context;
         m_componentHoldersByName = new HashMap();
         m_componentsById = new HashMap();
         m_componentCounter = -1;
 
+        // keep me informed on ConfigurationAdmin state changes
+        try
+        {
+            context.addServiceListener( this, "(objectclass=" + CONFIGURATION_ADMIN + ")" );
+        }
+        catch ( InvalidSyntaxException ise )
+        {
+            // not expected (filter is tested valid)
+        }
+
         // register as ScrService
         Dictionary props = new Hashtable();
         props.put( Constants.SERVICE_DESCRIPTION, "Declarative Services Management Agent" );
@@ -106,6 +131,14 @@
 
     public void dispose()
     {
+        m_bundleContext.removeServiceListener(this);
+
+        if (configurationSupport != null)
+        {
+            configurationSupport.dispose();
+            configurationSupport = null;
+        }
+
         if ( m_registration != null )
         {
             m_registration.unregister();
@@ -378,18 +411,69 @@
      */
     public ComponentHolder createComponentHolder( BundleComponentActivator activator, ComponentMetadata metadata )
     {
-        if ( metadata.isFactory() )
+        ComponentHolder holder;
+
+        if (metadata.isFactory())
         {
             // 112.2.4 SCR must register a Component Factory
             // service on behalf ot the component
             // as soon as the component factory is satisfied
-            return new ComponentFactoryImpl( activator, metadata );
+            holder = new ComponentFactoryImpl(activator, metadata);
+        }
+        else
+        {
+            holder = new ImmediateComponentHolder(activator, metadata);
         }
 
-        return new UnconfiguredComponentHolder( activator, metadata );
+        if (configurationSupport != null)
+        {
+            configurationSupport.configureComponentHolder(holder);
+        }
+
+        return holder;
     }
 
 
+    //---------- ServiceListener
+
+    /**
+     * Called if the Configuration Admin service changes state. This
+     * implementation is mainly interested in the Configuration Admin service
+     * being registered <i>after</i> the Declarative Services setup to be able
+     * to forward existing configuration.
+     *
+     * @param event The service change event
+     */
+    public void serviceChanged(ServiceEvent event)
+    {
+        if (event.getType() == ServiceEvent.REGISTERED)
+        {
+            this.configurationSupport = new ConfigurationSupport(this.m_bundleContext, this);
+
+            final ServiceReference caRef = event.getServiceReference();
+            final Object service = m_bundleContext.getService(caRef);
+            if (service != null)
+            {
+                try
+                {
+                    this.configurationSupport.configureComponentHolders(caRef, service);
+                }
+                finally
+                {
+                    m_bundleContext.ungetService(caRef);
+                }
+            }
+        }
+        else if (event.getType() == ServiceEvent.UNREGISTERING)
+        {
+            if (configurationSupport != null)
+            {
+                this.configurationSupport.dispose();
+                this.configurationSupport = null;
+            }
+        }
+    }
+
     //---------- Helper method
 
     /**
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/AbstractComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/AbstractComponentHolder.java
deleted file mode 100644
index 76a5b37..0000000
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/AbstractComponentHolder.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.config;
-
-
-import org.apache.felix.scr.impl.BundleComponentActivator;
-import org.apache.felix.scr.impl.manager.DelayedComponentManager;
-import org.apache.felix.scr.impl.manager.ImmediateComponentManager;
-import org.apache.felix.scr.impl.manager.ServiceFactoryComponentManager;
-import org.apache.felix.scr.impl.metadata.ComponentMetadata;
-
-
-abstract class AbstractComponentHolder implements ComponentHolder
-{
-
-    private final BundleComponentActivator m_activator;
-
-    private final ComponentMetadata m_componentMetadata;
-
-
-    public AbstractComponentHolder( final BundleComponentActivator activator, final ComponentMetadata metadata )
-    {
-        this.m_activator = activator;
-        this.m_componentMetadata = metadata;
-    }
-
-
-    protected ImmediateComponentManager createComponentManager()
-    {
-
-        ImmediateComponentManager manager;
-        if ( m_componentMetadata.isFactory() )
-        {
-            throw new IllegalArgumentException( "Cannot create component factory for " + m_componentMetadata.getName() );
-        }
-        else if ( m_componentMetadata.isImmediate() )
-        {
-            manager = new ImmediateComponentManager( m_activator, this, m_componentMetadata );
-        }
-        else if ( m_componentMetadata.getServiceMetadata() != null )
-        {
-            if ( m_componentMetadata.getServiceMetadata().isServiceFactory() )
-            {
-                manager = new ServiceFactoryComponentManager( m_activator, this, m_componentMetadata );
-            }
-            else
-            {
-                manager = new DelayedComponentManager( m_activator, this, m_componentMetadata );
-            }
-        }
-        else
-        {
-            // if we get here, which is not expected after all, we fail
-            throw new IllegalArgumentException( "Cannot create a component manager for "
-                + m_componentMetadata.getName() );
-        }
-
-        return manager;
-    }
-
-
-    public final BundleComponentActivator getActivator()
-    {
-        return m_activator;
-    }
-
-
-    public final ComponentMetadata getComponentMetadata()
-    {
-        return m_componentMetadata;
-    }
-
-
-    protected final String getComponentName()
-    {
-        return getComponentMetadata().getName();
-    }
-}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationComponentRegistry.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationComponentRegistry.java
deleted file mode 100644
index 64067be..0000000
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationComponentRegistry.java
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * 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.config;
-
-
-import java.io.IOException;
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.apache.felix.scr.impl.Activator;
-import org.apache.felix.scr.impl.BundleComponentActivator;
-import org.apache.felix.scr.impl.ComponentRegistry;
-import org.apache.felix.scr.impl.manager.ComponentFactoryImpl;
-import org.apache.felix.scr.impl.metadata.ComponentMetadata;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.cm.Configuration;
-import org.osgi.service.cm.ConfigurationAdmin;
-import org.osgi.service.cm.ConfigurationEvent;
-import org.osgi.service.cm.ConfigurationListener;
-import org.osgi.service.log.LogService;
-
-
-public class ConfigurationComponentRegistry extends ComponentRegistry implements ServiceListener, ConfigurationListener
-{
-
-    // the name of the ConfigurationAdmin service
-    private static final String CONFIGURATION_ADMIN = "org.osgi.service.cm.ConfigurationAdmin";
-
-    // the service m_registration of the ConfigurationListener service
-    private ServiceRegistration m_registration;
-
-    // the bundle context
-    private BundleContext m_bundleContext;
-
-
-    public ConfigurationComponentRegistry( final BundleContext context )
-    {
-        super( context );
-        m_bundleContext = context;
-
-        // register as listener for configurations
-        Dictionary props = new Hashtable();
-        props.put( Constants.SERVICE_DESCRIPTION, "Declarative Services Configuration Support Listener" );
-        props.put( Constants.SERVICE_VENDOR, "The Apache Software Foundation" );
-        m_registration = context.registerService( new String[]
-            { ConfigurationListener.class.getName() }, this, props );
-
-        // keep me informed on ConfigurationAdmin state changes
-        try
-        {
-            context.addServiceListener( this, "(objectclass=" + CONFIGURATION_ADMIN + ")" );
-        }
-        catch ( InvalidSyntaxException ise )
-        {
-            // not expected (filter is tested valid)
-        }
-    }
-
-
-    public void dispose()
-    {
-        m_bundleContext.removeServiceListener( this );
-
-        if ( m_registration != null )
-        {
-            m_registration.unregister();
-            m_registration = null;
-        }
-
-        super.dispose();
-    }
-
-
-    //---------- BaseConfigurationSupport overwrites
-
-    public ComponentHolder createComponentHolder( final BundleComponentActivator activator,
-        final ComponentMetadata metadata )
-    {
-        // 112.7 configure unless configuration not required
-        if ( metadata.isConfigurationIgnored() )
-        {
-            return super.createComponentHolder( activator, metadata );
-        }
-
-        // prepare the configuration holder
-        final ComponentHolder holder;
-        if ( metadata.isFactory() )
-        {
-            holder = new ComponentFactoryImpl( activator, metadata );
-        }
-        else
-        {
-            holder = new ConfiguredComponentHolder( activator, metadata );
-        }
-
-        final BundleContext bundleContext = activator.getBundleContext();
-        final String bundleLocation = bundleContext.getBundle().getLocation();
-        final String name = metadata.getName();
-
-        final ServiceReference caRef = bundleContext.getServiceReference( CONFIGURATION_ADMIN );
-        if ( caRef != null )
-        {
-            final ConfigurationAdmin ca = ( ConfigurationAdmin ) bundleContext.getService( caRef );
-            if ( ca != null )
-            {
-                try
-                {
-                    final Configuration[] factory = findFactoryConfigurations( ca, name );
-                    if ( factory != null )
-                    {
-                        for ( int i = 0; i < factory.length; i++ )
-                        {
-                            final String pid = factory[i].getPid();
-                            final Dictionary props = getConfiguration( ca, pid, bundleLocation );
-                            holder.configurationUpdated( pid, props );
-                        }
-                    }
-                    else
-                    {
-                        // check for configuration and configure the holder
-                        final Configuration singleton = findSingletonConfiguration( ca, name );
-                        if ( singleton != null )
-                        {
-                            final Dictionary props = getConfiguration( ca, name, bundleLocation );
-                            holder.configurationUpdated( name, props );
-                        }
-                    }
-                }
-                finally
-                {
-                    bundleContext.ungetService( caRef );
-                }
-            }
-        }
-
-        return holder;
-    }
-
-
-    //---------- ServiceListener
-
-    /**
-     * Called if the Configuration Admin service changes state. This
-     * implementation is mainly interested in the Configuration Admin service
-     * being registered <i>after</i> the Declarative Services setup to be able
-     * to forward existing configuration.
-     *
-     * @param event The service change event
-     */
-    public void serviceChanged( ServiceEvent event )
-    {
-        if ( event.getType() == ServiceEvent.REGISTERED )
-        {
-            Configuration[] configs = null;
-            final ServiceReference caRef = event.getServiceReference();
-            final Object service = m_bundleContext.getService( caRef );
-            try
-            {
-                if ( service instanceof ConfigurationAdmin )
-                {
-                    configs = findConfigurations( ( ConfigurationAdmin ) service, null );
-                }
-            }
-            finally
-            {
-                if ( service != null )
-                {
-                    m_bundleContext.ungetService( caRef );
-                }
-            }
-
-            if ( configs != null )
-            {
-                for ( int i = 0; i < configs.length; i++ )
-                {
-                    ConfigurationEvent cfgEvent = new ConfigurationEvent( caRef, ConfigurationEvent.CM_UPDATED,
-                        configs[i].getFactoryPid(), configs[i].getPid() );
-                    configurationEvent( cfgEvent );
-                }
-            }
-        }
-    }
-
-
-    //---------- ConfigurationListener
-
-    /**
-     * Called by the Configuration Admin service if a configuration is updated
-     * or removed.
-     * <p>
-     * This method is really only called upon configuration changes; it is not
-     * called for existing configurations upon startup of the Configuration
-     * Admin service. To bridge this gap, the
-     * {@link #serviceChanged(ServiceEvent)} method called when the
-     * Configuration Admin service is registered calls this method for all
-     * existing configurations to be able to foward existing configurations
-     * to components.
-     *
-     * @param event The configuration change event
-     */
-    public void configurationEvent( ConfigurationEvent event )
-    {
-        final String pid = event.getPid();
-        final String factoryPid = event.getFactoryPid();
-
-        final ComponentHolder cm;
-        if ( factoryPid == null )
-        {
-            cm = getComponentHolder( pid );
-        }
-        else
-        {
-            cm = getComponentHolder( factoryPid );
-        }
-
-        Activator.log( LogService.LOG_DEBUG, null, "configurationEvent: Handling "
-            + ( ( event.getType() == ConfigurationEvent.CM_DELETED ) ? "DELETE" : "UPDATE" ) + " of Configuration PID="
-            + pid, null );
-
-        if ( cm != null && !cm.getComponentMetadata().isConfigurationIgnored() )
-        {
-            switch ( event.getType() )
-            {
-                case ConfigurationEvent.CM_DELETED:
-                    cm.configurationDeleted( pid );
-                    break;
-
-                case ConfigurationEvent.CM_UPDATED:
-                    final BundleComponentActivator activator = cm.getActivator();
-                    if ( activator == null )
-                    {
-                        break;
-                    }
-
-                    final BundleContext bundleContext = activator.getBundleContext();
-                    if ( bundleContext == null )
-                    {
-                        break;
-                    }
-
-                    final ServiceReference caRef = bundleContext.getServiceReference( CONFIGURATION_ADMIN );
-                    if ( caRef != null )
-                    {
-                        try
-                        {
-                            final ConfigurationAdmin ca = ( ConfigurationAdmin ) bundleContext.getService( caRef );
-                            if ( ca != null )
-                            {
-                                try
-                                {
-                                    final Dictionary dict = getConfiguration( ca, pid, bundleContext.getBundle()
-                                        .getLocation() );
-                                    if ( dict != null )
-                                    {
-                                        cm.configurationUpdated( pid, dict );
-                                    }
-                                }
-                                finally
-                                {
-                                    bundleContext.ungetService( caRef );
-                                }
-                            }
-                        }
-                        catch ( IllegalStateException ise )
-                        {
-                            // If the bundle has been stopped conurrently
-                        }
-                    }
-                    break;
-
-                default:
-                    Activator.log( LogService.LOG_WARNING, null, "Unknown ConfigurationEvent type " + event.getType(),
-                        null );
-            }
-        }
-    }
-
-
-    private Dictionary getConfiguration( final ConfigurationAdmin ca, final String pid, final String bundleLocation )
-    {
-        try
-        {
-            final Configuration cfg = ca.getConfiguration( pid );
-            if ( bundleLocation.equals( cfg.getBundleLocation() ) || Activator.hasCtWorkaround() )
-            {
-                return cfg.getProperties();
-            }
-
-            // configuration belongs to another bundle, cannot be used here
-            Activator.log( LogService.LOG_ERROR, null, "Cannot use configuration pid=" + pid + " for bundle "
-                + bundleLocation + " because it belongs to bundle " + cfg.getBundleLocation(), null );
-        }
-        catch ( IOException ioe )
-        {
-            Activator.log( LogService.LOG_WARNING, null, "Failed reading configuration for pid=" + pid, ioe );
-        }
-
-        return null;
-    }
-
-
-    /**
-     * Returns the configuration whose PID equals the given pid. If no such
-     * configuration exists, <code>null</code> is returned.
-     * @param ctx
-     * @param pid
-     * @return
-     */
-    public Configuration findSingletonConfiguration( final ConfigurationAdmin ca, final String pid )
-    {
-        final String filter = "(service.pid=" + pid + ")";
-        final Configuration[] cfg = findConfigurations( ca, filter );
-        return ( cfg == null || cfg.length == 0 ) ? null : cfg[0];
-    }
-
-
-    /**
-     * Returns all configurations whose factory PID equals the given factory PID
-     * or <code>null</code> if no such configurations exist
-     * @param ctx
-     * @param factoryPid
-     * @return
-     */
-    public Configuration[] findFactoryConfigurations( final ConfigurationAdmin ca, final String factoryPid )
-    {
-        final String filter = "(service.factoryPid=" + factoryPid + ")";
-        return findConfigurations( ca, filter );
-    }
-
-
-    private Configuration[] findConfigurations( final ConfigurationAdmin ca, final String filter )
-    {
-        try
-        {
-            return ca.listConfigurations( filter );
-        }
-        catch ( IOException ioe )
-        {
-            Activator.log( LogService.LOG_WARNING, null, "Problem listing configurations for filter=" + filter, ioe );
-        }
-        catch ( InvalidSyntaxException ise )
-        {
-            Activator.log( LogService.LOG_ERROR, null, "Invalid Configuration selection filter " + filter, ise );
-        }
-
-        // no factories in case of problems
-        return null;
-    }
-}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
new file mode 100644
index 0000000..bdd8bf9
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationSupport.java
@@ -0,0 +1,301 @@
+/*
+ * 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.config;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.scr.impl.Activator;
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.ComponentRegistry;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
+import org.osgi.service.log.LogService;
+
+public class ConfigurationSupport implements ConfigurationListener
+{
+
+    final ComponentRegistry m_registry;
+
+    // the service m_registration of the ConfigurationListener service
+    private ServiceRegistration m_registration;
+
+    public ConfigurationSupport(final BundleContext bundleContext, final ComponentRegistry registry)
+    {
+        this.m_registry = registry;
+
+        // register as listener for configurations
+        Dictionary props = new Hashtable();
+        props.put(Constants.SERVICE_DESCRIPTION, "Declarative Services Configuration Support Listener");
+        props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
+        this.m_registration = bundleContext.registerService(new String[]
+            { "org.osgi.service.cm.ConfigurationListener" }, this, props);
+    }
+
+    public void dispose()
+    {
+        if (this.m_registration != null)
+        {
+            this.m_registration.unregister();
+            this.m_registration = null;
+        }
+    }
+
+    // ---------- BaseConfigurationSupport overwrites
+
+    public void configureComponentHolder(final ComponentHolder holder)
+    {
+
+        // 112.7 configure unless configuration not required
+        if (!holder.getComponentMetadata().isConfigurationIgnored())
+        {
+            final BundleContext bundleContext = holder.getActivator().getBundleContext();
+            final String bundleLocation = bundleContext.getBundle().getLocation();
+            final String name = holder.getComponentMetadata().getName();
+
+            final ServiceReference caRef = bundleContext.getServiceReference(ComponentRegistry.CONFIGURATION_ADMIN);
+            if (caRef != null)
+            {
+                final ConfigurationAdmin ca = (ConfigurationAdmin) bundleContext.getService(caRef);
+                if (ca != null)
+                {
+                    try
+                    {
+                        final Configuration[] factory = findFactoryConfigurations(ca, name);
+                        if (factory != null)
+                        {
+                            for (int i = 0; i < factory.length; i++)
+                            {
+                                final String pid = factory[i].getPid();
+                                final Dictionary props = getConfiguration(ca, pid, bundleLocation);
+                                holder.configurationUpdated(pid, props);
+                            }
+                        }
+                        else
+                        {
+                            // check for configuration and configure the holder
+                            final Configuration singleton = findSingletonConfiguration(ca, name);
+                            if (singleton != null)
+                            {
+                                final Dictionary props = getConfiguration(ca, name, bundleLocation);
+                                holder.configurationUpdated(name, props);
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        bundleContext.ungetService(caRef);
+                    }
+                }
+            }
+        }
+    }
+
+    // ---------- ServiceListener
+
+    public void configureComponentHolders(final ServiceReference configurationAdminReference,
+        final Object configurationAdmin)
+    {
+        if (configurationAdmin instanceof ConfigurationAdmin)
+        {
+            Configuration[] configs = findConfigurations((ConfigurationAdmin) configurationAdmin, null);
+            if (configs != null)
+            {
+                for (int i = 0; i < configs.length; i++)
+                {
+                    ConfigurationEvent cfgEvent = new ConfigurationEvent(configurationAdminReference,
+                        ConfigurationEvent.CM_UPDATED, configs[i].getFactoryPid(), configs[i].getPid());
+                    configurationEvent(cfgEvent);
+                }
+            }
+        }
+    }
+
+    // ---------- ConfigurationListener
+
+    /**
+     * Called by the Configuration Admin service if a configuration is updated
+     * or removed.
+     * <p>
+     * This method is really only called upon configuration changes; it is not
+     * called for existing configurations upon startup of the Configuration
+     * Admin service. To bridge this gap, the
+     * {@link #serviceChanged(ServiceEvent)} method called when the
+     * Configuration Admin service is registered calls this method for all
+     * existing configurations to be able to foward existing configurations to
+     * components.
+     *
+     * @param event The configuration change event
+     */
+    public void configurationEvent(ConfigurationEvent event)
+    {
+        final String pid = event.getPid();
+        final String factoryPid = event.getFactoryPid();
+
+        final ComponentHolder cm;
+        if (factoryPid == null)
+        {
+            cm = this.m_registry.getComponentHolder(pid);
+        }
+        else
+        {
+            cm = this.m_registry.getComponentHolder(factoryPid);
+        }
+
+        Activator.log(LogService.LOG_DEBUG, null, "configurationEvent: Handling "
+            + ((event.getType() == ConfigurationEvent.CM_DELETED) ? "DELETE" : "UPDATE") + " of Configuration PID="
+            + pid, null);
+
+        if (cm != null && !cm.getComponentMetadata().isConfigurationIgnored())
+        {
+            switch (event.getType())
+            {
+                case ConfigurationEvent.CM_DELETED:
+                    cm.configurationDeleted(pid);
+                    break;
+
+                case ConfigurationEvent.CM_UPDATED:
+                    final BundleComponentActivator activator = cm.getActivator();
+                    if (activator == null)
+                    {
+                        break;
+                    }
+
+                    final BundleContext bundleContext = activator.getBundleContext();
+                    if (bundleContext == null)
+                    {
+                        break;
+                    }
+
+                    final ServiceReference caRef = bundleContext
+                        .getServiceReference(ComponentRegistry.CONFIGURATION_ADMIN);
+                    if (caRef != null)
+                    {
+                        try
+                        {
+                            final ConfigurationAdmin ca = (ConfigurationAdmin) bundleContext.getService(caRef);
+                            if (ca != null)
+                            {
+                                try
+                                {
+                                    final Dictionary dict = getConfiguration(ca, pid, bundleContext.getBundle()
+                                        .getLocation());
+                                    if (dict != null)
+                                    {
+                                        cm.configurationUpdated(pid, dict);
+                                    }
+                                }
+                                finally
+                                {
+                                    bundleContext.ungetService(caRef);
+                                }
+                            }
+                        }
+                        catch (IllegalStateException ise)
+                        {
+                            // If the bundle has been stopped conurrently
+                        }
+                    }
+                    break;
+
+                default:
+                    Activator.log(LogService.LOG_WARNING, null, "Unknown ConfigurationEvent type " + event.getType(),
+                        null);
+            }
+        }
+    }
+
+    private Dictionary getConfiguration(final ConfigurationAdmin ca, final String pid, final String bundleLocation)
+    {
+        try
+        {
+            final Configuration cfg = ca.getConfiguration(pid);
+            if (bundleLocation.equals(cfg.getBundleLocation()) || Activator.hasCtWorkaround())
+            {
+                return cfg.getProperties();
+            }
+
+            // configuration belongs to another bundle, cannot be used here
+            Activator.log(LogService.LOG_ERROR, null, "Cannot use configuration pid=" + pid + " for bundle "
+                + bundleLocation + " because it belongs to bundle " + cfg.getBundleLocation(), null);
+        }
+        catch (IOException ioe)
+        {
+            Activator.log(LogService.LOG_WARNING, null, "Failed reading configuration for pid=" + pid, ioe);
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the configuration whose PID equals the given pid. If no such
+     * configuration exists, <code>null</code> is returned.
+     *
+     * @param ctx
+     * @param pid
+     * @return
+     */
+    public Configuration findSingletonConfiguration(final ConfigurationAdmin ca, final String pid)
+    {
+        final String filter = "(service.pid=" + pid + ")";
+        final Configuration[] cfg = findConfigurations(ca, filter);
+        return (cfg == null || cfg.length == 0) ? null : cfg[0];
+    }
+
+    /**
+     * Returns all configurations whose factory PID equals the given factory PID
+     * or <code>null</code> if no such configurations exist
+     *
+     * @param ctx
+     * @param factoryPid
+     * @return
+     */
+    public Configuration[] findFactoryConfigurations(final ConfigurationAdmin ca, final String factoryPid)
+    {
+        final String filter = "(service.factoryPid=" + factoryPid + ")";
+        return findConfigurations(ca, filter);
+    }
+
+    private Configuration[] findConfigurations(final ConfigurationAdmin ca, final String filter)
+    {
+        try
+        {
+            return ca.listConfigurations(filter);
+        }
+        catch (IOException ioe)
+        {
+            Activator.log(LogService.LOG_WARNING, null, "Problem listing configurations for filter=" + filter, ioe);
+        }
+        catch (InvalidSyntaxException ise)
+        {
+            Activator.log(LogService.LOG_ERROR, null, "Invalid Configuration selection filter " + filter, ise);
+        }
+
+        // no factories in case of problems
+        return null;
+    }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java
similarity index 85%
rename from scr/src/main/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolder.java
rename to scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java
index 2c44470..8d9b3f5 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolder.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ImmediateComponentHolder.java
@@ -26,7 +26,9 @@
 
 import org.apache.felix.scr.Component;
 import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.manager.DelayedComponentManager;
 import org.apache.felix.scr.impl.manager.ImmediateComponentManager;
+import org.apache.felix.scr.impl.manager.ServiceFactoryComponentManager;
 import org.apache.felix.scr.impl.metadata.ComponentMetadata;
 import org.osgi.service.component.ComponentConstants;
 
@@ -52,10 +54,20 @@
  * <code>service.factoryPid</code> equals the component name.</li>
  * </ul>
  */
-public class ConfiguredComponentHolder extends AbstractComponentHolder
+public class ImmediateComponentHolder implements ComponentHolder
 {
 
     /**
+     * The activator owning the per-bundle components
+     */
+    private final BundleComponentActivator m_activator;
+
+    /**
+     * The {@link ComponentMetadata} describing the held component(s)
+     */
+    private final ComponentMetadata m_componentMetadata;
+
+    /**
      * A map of components configured with factory configuration. The indices
      * are the PIDs (<code>service.pid</code>) of the configuration objects.
      * The values are the {@link ImmediateComponentManager component instances}
@@ -91,15 +103,60 @@
     private boolean m_enabled;
 
 
-    ConfiguredComponentHolder( final BundleComponentActivator activator, final ComponentMetadata metadata )
+    public ImmediateComponentHolder( final BundleComponentActivator activator, final ComponentMetadata metadata )
     {
-        super( activator, metadata );
-
+        this.m_activator = activator;
+        this.m_componentMetadata = metadata;
         this.m_components = new HashMap();
         this.m_singleComponent = createComponentManager();
         this.m_enabled = false;
     }
 
+    protected ImmediateComponentManager createComponentManager()
+    {
+
+        ImmediateComponentManager manager;
+        if ( m_componentMetadata.isFactory() )
+        {
+            throw new IllegalArgumentException( "Cannot create component factory for " + m_componentMetadata.getName() );
+        }
+        else if ( m_componentMetadata.isImmediate() )
+        {
+            manager = new ImmediateComponentManager( m_activator, this, m_componentMetadata );
+        }
+        else if ( m_componentMetadata.getServiceMetadata() != null )
+        {
+            if ( m_componentMetadata.getServiceMetadata().isServiceFactory() )
+            {
+                manager = new ServiceFactoryComponentManager( m_activator, this, m_componentMetadata );
+            }
+            else
+            {
+                manager = new DelayedComponentManager( m_activator, this, m_componentMetadata );
+            }
+        }
+        else
+        {
+            // if we get here, which is not expected after all, we fail
+            throw new IllegalArgumentException( "Cannot create a component manager for "
+                + m_componentMetadata.getName() );
+        }
+
+        return manager;
+    }
+
+
+    public final BundleComponentActivator getActivator()
+    {
+        return m_activator;
+    }
+
+
+    public final ComponentMetadata getComponentMetadata()
+    {
+        return m_componentMetadata;
+    }
+
 
     /**
      * The configuration with the given <code>pid</code>
@@ -128,7 +185,7 @@
             return;
         }
 
-        if ( pid.equals( getComponentName() ) )
+        if ( pid.equals( getComponentMetadata().getName() ) )
         {
             // singleton configuration deleted
             m_singleComponent.reconfigure( null );
@@ -195,7 +252,7 @@
             return;
         }
 
-        if ( pid.equals( getComponentName() ) )
+        if ( pid.equals( getComponentMetadata().getName() ) )
         {
             // singleton configuration has pid equal to component name
             m_singleComponent.reconfigure( props );
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/MetaTypeProviderImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/config/MetaTypeProviderImpl.java
deleted file mode 100644
index 933c9c6..0000000
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/MetaTypeProviderImpl.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * 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.config;
-
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Dictionary;
-
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
-import org.osgi.service.metatype.AttributeDefinition;
-import org.osgi.service.metatype.MetaTypeProvider;
-import org.osgi.service.metatype.ObjectClassDefinition;
-
-public class MetaTypeProviderImpl
-    implements MetaTypeProvider, ManagedService
-{
-
-    private final int logLevel;
-
-    private final boolean factoryEnabled;
-
-    private final ManagedService delegatee;
-
-    public MetaTypeProviderImpl(final int logLevel,
-                                final boolean factoryEnabled,
-                                final ManagedService delegatee)
-    {
-        this.logLevel = logLevel;
-        this.factoryEnabled = factoryEnabled;
-        this.delegatee = delegatee;
-    }
-
-    private ObjectClassDefinition ocd;
-
-    public void updated(Dictionary properties) throws ConfigurationException
-    {
-        this.delegatee.updated(properties);
-    }
-
-    /**
-     * @see org.osgi.service.metatype.MetaTypeProvider#getLocales()
-     */
-    public String[] getLocales()
-    {
-        return null;
-    }
-
-    /**
-     * @see org.osgi.service.metatype.MetaTypeProvider#getObjectClassDefinition(java.lang.String, java.lang.String)
-     */
-    public ObjectClassDefinition getObjectClassDefinition( String id, String locale )
-    {
-        if ( !ScrConfiguration.PID.equals( id ) )
-        {
-            return null;
-        }
-
-        if ( ocd == null )
-        {
-            final ArrayList adList = new ArrayList();
-
-            adList.add( new AttributeDefinitionImpl( ScrConfiguration.PROP_LOGLEVEL, "SCR Log Level",
-                    "Allows limiting the amount of logging information sent to the OSGi LogService." +
-                    " Supported values are DEBUG, INFO, WARN, and ERROR. Default is ERROR.",
-                    AttributeDefinition.INTEGER,
-                    new String[] {String.valueOf(this.logLevel)}, 0,
-                    new String[] {"Debug", "Information", "Warnings", "Error"},
-                    new String[] {"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.factoryEnabled ) );
-
-            ocd = new ObjectClassDefinition()
-            {
-
-                private final AttributeDefinition[] attrs = ( AttributeDefinition[] ) adList
-                    .toArray( new AttributeDefinition[adList.size()] );
-
-
-                public String getName()
-                {
-                    return "Apache Felix Declarative Service Implementation";
-                }
-
-
-                public InputStream getIcon( int arg0 )
-                {
-                    return null;
-                }
-
-
-                public String getID()
-                {
-                    return ScrConfiguration.PID;
-                }
-
-
-                public String getDescription()
-                {
-                    return "Configuration for the Apache Felix Declarative Services Implementation." +
-                           " This configuration overwrites configuration defined in framework properties of the same names.";
-                }
-
-
-                public AttributeDefinition[] getAttributeDefinitions( int filter )
-                {
-                    return ( filter == OPTIONAL ) ? null : attrs;
-                }
-            };
-        }
-
-        return ocd;
-    }
-
-    class AttributeDefinitionImpl implements AttributeDefinition
-    {
-
-        private final String id;
-        private final String name;
-        private final String description;
-        private final int type;
-        private final String[] defaultValues;
-        private final int cardinality;
-        private final String[] optionLabels;
-        private final String[] optionValues;
-
-
-        AttributeDefinitionImpl( final String id, final String name, final String description, final boolean defaultValue )
-        {
-            this( id, name, description, BOOLEAN, new String[]
-                { String.valueOf(defaultValue) }, 0, null, null );
-        }
-
-        AttributeDefinitionImpl( final String id, final String name, final String description, final int type,
-            final String[] defaultValues, final int cardinality, final String[] optionLabels,
-            final String[] optionValues )
-        {
-            this.id = id;
-            this.name = name;
-            this.description = description;
-            this.type = type;
-            this.defaultValues = defaultValues;
-            this.cardinality = cardinality;
-            this.optionLabels = optionLabels;
-            this.optionValues = optionValues;
-        }
-
-
-        public int getCardinality()
-        {
-            return cardinality;
-        }
-
-
-        public String[] getDefaultValue()
-        {
-            return defaultValues;
-        }
-
-
-        public String getDescription()
-        {
-            return description;
-        }
-
-
-        public String getID()
-        {
-            return id;
-        }
-
-
-        public String getName()
-        {
-            return name;
-        }
-
-
-        public String[] getOptionLabels()
-        {
-            return optionLabels;
-        }
-
-
-        public String[] getOptionValues()
-        {
-            return optionValues;
-        }
-
-
-        public int getType()
-        {
-            return type;
-        }
-
-
-        public String validate( String arg0 )
-        {
-            return null;
-        }
-    }
-}
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 8428750..986e687 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
@@ -25,10 +25,7 @@
 import org.apache.felix.scr.impl.Activator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
 import org.osgi.service.log.LogService;
-import org.osgi.service.metatype.MetaTypeProvider;
 
 
 /**
@@ -68,8 +65,6 @@
 
     private boolean factoryEnabled;
 
-    private boolean ctWorkaround;
-
     static final String PID = "org.apache.felix.scr.ScrService";
 
     public ScrConfiguration( BundleContext bundleContext )
@@ -80,35 +75,12 @@
         configure( null );
 
         // listen for Configuration Admin configuration
-        try
-        {
-            Object service = new ManagedService()
-            {
-                public void updated( Dictionary properties ) throws ConfigurationException
-                {
-                    configure( properties );
-                }
-            };
-            // add meta type provider if interfaces are available
-            Object enhancedService = tryToCreateMetaTypeProvider(service);
-            final String[] interfaceNames;
-            if ( enhancedService == null )
-            {
-                interfaceNames = new String[] {ManagedService.class.getName()};
-            }
-            else
-            {
-                interfaceNames = new String[] {ManagedService.class.getName(), MetaTypeProvider.class.getName()};
-                service = enhancedService;
-            }
-            Dictionary props = new Hashtable();
-            props.put( Constants.SERVICE_PID, PID );
-            bundleContext.registerService( interfaceNames, service, props );
-        }
-        catch ( Throwable t )
-        {
-            // don't care
-        }
+        Dictionary props = new Hashtable();
+        props.put(Constants.SERVICE_PID, PID);
+        props.put(Constants.SERVICE_DESCRIPTION, "SCR Configurator");
+        props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
+        bundleContext.registerService("org.osgi.service.cm.ManagedService", new ScrManagedServiceServiceFactory(this),
+            props);
     }
 
     void configure( Dictionary config )
@@ -223,19 +195,4 @@
         // default log level (errors only)
         return LogService.LOG_ERROR;
     }
-
-
-    private Object tryToCreateMetaTypeProvider( final Object managedService )
-    {
-        try
-        {
-            return new MetaTypeProviderImpl( getDefaultLogLevel(), getDefaultFactoryEnabled(),
-                ( ManagedService ) managedService );
-        }
-        catch ( Throwable t )
-        {
-            // we simply ignore this
-        }
-        return null;
-    }
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedService.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedService.java
new file mode 100644
index 0000000..c6b51f7
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedService.java
@@ -0,0 +1,51 @@
+/*
+ * 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.config;
+
+import java.util.Dictionary;
+
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ * The <code>ScrManagedService</code> receives configuration for the Declarative
+ * Services Runtime itself. This class is instantiated in a ServiceFactory
+ * manner by the {@link ScrManagedServiceServiceFactory} when the Configuration
+ * Admin service implementation and API is available.
+ */
+public class ScrManagedService implements ManagedService
+{
+
+    private final ScrConfiguration scrConfiguration;
+
+    protected final ScrConfiguration getScrConfiguration()
+    {
+        return scrConfiguration;
+    }
+
+    public ScrManagedService(final ScrConfiguration scrConfiguration)
+    {
+        this.scrConfiguration = scrConfiguration;
+    }
+
+    public void updated(Dictionary properties) throws ConfigurationException
+    {
+        this.scrConfiguration.configure(properties);
+    }
+}
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
new file mode 100644
index 0000000..afbe66d
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceMetaTypeProvider.java
@@ -0,0 +1,207 @@
+/*
+ * 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.config;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.metatype.AttributeDefinition;
+import org.osgi.service.metatype.MetaTypeProvider;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+/**
+ * The <code>ScrManagedServiceMetaTypeProvider</code> receives the Declarative
+ * Services Runtime configuration (by extending the {@link ScrManagedService}
+ * class but also provides a MetaType Service ObjectClassDefinition.
+ */
+class ScrManagedServiceMetaTypeProvider extends ScrManagedService
+    implements MetaTypeProvider
+{
+
+    static ManagedService create(final ScrConfiguration scrConfiguration)
+    {
+        return new ScrManagedServiceMetaTypeProvider(scrConfiguration);
+    }
+
+    private ScrManagedServiceMetaTypeProvider(final ScrConfiguration scrConfiguration)
+    {
+        super(scrConfiguration);
+    }
+
+    /**
+     * @see org.osgi.service.metatype.MetaTypeProvider#getLocales()
+     */
+    public String[] getLocales()
+    {
+        return null;
+    }
+
+    /**
+     * @see org.osgi.service.metatype.MetaTypeProvider#getObjectClassDefinition(java.lang.String, java.lang.String)
+     */
+    public ObjectClassDefinition getObjectClassDefinition( String id, String locale )
+    {
+        if ( !ScrConfiguration.PID.equals( id ) )
+        {
+            return null;
+        }
+
+        final ArrayList adList = new ArrayList();
+
+        adList.add(new AttributeDefinitionImpl(ScrConfiguration.PROP_LOGLEVEL, "SCR Log Level",
+            "Allows limiting the amount of logging information sent to the OSGi LogService."
+                + " Supported values are DEBUG, INFO, WARN, and ERROR. Default is ERROR.", AttributeDefinition.INTEGER,
+            new String[]
+                { String.valueOf(this.getScrConfiguration().getLogLevel()) }, 0, new String[]
+                { "Debug", "Information", "Warnings", "Error" }, new String[]
+                { "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()));
+
+        return new ObjectClassDefinition()
+        {
+
+            private final AttributeDefinition[] attrs = (AttributeDefinition[]) adList
+                .toArray(new AttributeDefinition[adList.size()]);
+
+            public String getName()
+            {
+                return "Apache Felix Declarative Service Implementation";
+            }
+
+            public InputStream getIcon(int arg0)
+            {
+                return null;
+            }
+
+            public String getID()
+            {
+                return ScrConfiguration.PID;
+            }
+
+            public String getDescription()
+            {
+                return "Configuration for the Apache Felix Declarative Services Implementation."
+                    + " This configuration overwrites configuration defined in framework properties of the same names.";
+            }
+
+            public AttributeDefinition[] getAttributeDefinitions(int filter)
+            {
+                return (filter == OPTIONAL) ? null : attrs;
+            }
+        };
+    }
+
+    private static class AttributeDefinitionImpl implements AttributeDefinition
+    {
+
+        private final String id;
+        private final String name;
+        private final String description;
+        private final int type;
+        private final String[] defaultValues;
+        private final int cardinality;
+        private final String[] optionLabels;
+        private final String[] optionValues;
+
+
+        AttributeDefinitionImpl( final String id, final String name, final String description, final boolean defaultValue )
+        {
+            this( id, name, description, BOOLEAN, new String[]
+                { String.valueOf(defaultValue) }, 0, null, null );
+        }
+
+        AttributeDefinitionImpl( final String id, final String name, final String description, final int type,
+            final String[] defaultValues, final int cardinality, final String[] optionLabels,
+            final String[] optionValues )
+        {
+            this.id = id;
+            this.name = name;
+            this.description = description;
+            this.type = type;
+            this.defaultValues = defaultValues;
+            this.cardinality = cardinality;
+            this.optionLabels = optionLabels;
+            this.optionValues = optionValues;
+        }
+
+
+        public int getCardinality()
+        {
+            return cardinality;
+        }
+
+
+        public String[] getDefaultValue()
+        {
+            return defaultValues;
+        }
+
+
+        public String getDescription()
+        {
+            return description;
+        }
+
+
+        public String getID()
+        {
+            return id;
+        }
+
+
+        public String getName()
+        {
+            return name;
+        }
+
+
+        public String[] getOptionLabels()
+        {
+            return optionLabels;
+        }
+
+
+        public String[] getOptionValues()
+        {
+            return optionValues;
+        }
+
+
+        public int getType()
+        {
+            return type;
+        }
+
+
+        public String validate( String arg0 )
+        {
+            return null;
+        }
+    }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java
new file mode 100644
index 0000000..2128fb6
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ScrManagedServiceServiceFactory.java
@@ -0,0 +1,67 @@
+/*
+ * 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.config;
+
+import org.apache.felix.scr.impl.Activator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.log.LogService;
+
+/**
+ * The <code>ScrManagedServiceServiceFactory</code> is the ServiceFactory
+ * registered on behalf of the {@link ScrManagedService} (or
+ * {@link ScrManagedServiceMetaTypeProvider}, resp.) to create the instance on
+ * demand once it is used by the Configuration Admin Service or the MetaType
+ * Service.
+ * <p>
+ * In contrast to the {@link ScrManagedService} and
+ * {@link ScrManagedServiceMetaTypeProvider} classes, this class only requires
+ * core OSGi API and thus may be instantiated without the Configuration Admin
+ * and/or MetaType Service API actually available at the time of instantiation.
+ */
+public class ScrManagedServiceServiceFactory implements ServiceFactory
+{
+    private final ScrConfiguration scrConfiguration;
+
+    public ScrManagedServiceServiceFactory(final ScrConfiguration scrConfiguration)
+    {
+        this.scrConfiguration = scrConfiguration;
+    }
+
+    public Object getService(Bundle bundle, ServiceRegistration registration)
+    {
+        try
+        {
+            return ScrManagedServiceMetaTypeProvider.create(this.scrConfiguration);
+        }
+        catch (Throwable t)
+        {
+            // assume MetaType Service API not available
+            Activator.log(LogService.LOG_ERROR, null, "Cannot create MetaType providing ManagedService", t);
+        }
+        return new ScrManagedService(this.scrConfiguration);
+    }
+
+    public void ungetService(Bundle bundle, ServiceRegistration registration, Object service)
+    {
+        // nothing really todo; GC will do the rest
+    }
+
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/UnconfiguredComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/UnconfiguredComponentHolder.java
deleted file mode 100644
index 0b53cd8..0000000
--- a/scr/src/main/java/org/apache/felix/scr/impl/config/UnconfiguredComponentHolder.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.config;
-
-
-import java.util.Dictionary;
-
-import org.apache.felix.scr.Component;
-import org.apache.felix.scr.impl.BundleComponentActivator;
-import org.apache.felix.scr.impl.manager.ImmediateComponentManager;
-import org.apache.felix.scr.impl.metadata.ComponentMetadata;
-
-
-/**
- * The <code>SingletonHolder</code> class is {@link ComponentHolder} for a
- * component configured by a singleton configuration or no configuration
- * at all.
- */
-public class UnconfiguredComponentHolder extends AbstractComponentHolder
-{
-
-    private final ImmediateComponentManager m_component;
-
-
-    public UnconfiguredComponentHolder( BundleComponentActivator activator, ComponentMetadata metadata )
-    {
-        super( activator, metadata );
-
-        m_component = createComponentManager();
-    }
-
-
-    public void configurationDeleted( String pid )
-    {
-    }
-
-
-    public void configurationUpdated( String pid, Dictionary props )
-    {
-    }
-
-
-    public Component[] getComponents()
-    {
-        return new Component[]
-            { m_component };
-    }
-
-
-    public void enableComponents()
-    {
-        m_component.enable();
-    }
-
-
-    public void disableComponents()
-    {
-        m_component.disable();
-    }
-
-
-    public void disposeComponents( int reason )
-    {
-        m_component.dispose( reason );
-    }
-
-
-    public void disposed( ImmediateComponentManager component )
-    {
-        // nothing to do here...
-    }
-}
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolderTest.java b/scr/src/test/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolderTest.java
index 54e2e3f..30e6a60 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolderTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolderTest.java
@@ -178,11 +178,11 @@
     }
 
 
-    private static ImmediateComponentManager getSingleManager( ConfiguredComponentHolder holder )
+    private static ImmediateComponentManager getSingleManager( ImmediateComponentHolder holder )
     {
         try
         {
-            final Field f = ConfiguredComponentHolder.class.getDeclaredField( "m_singleComponent" );
+            final Field f = ImmediateComponentHolder.class.getDeclaredField( "m_singleComponent" );
             f.setAccessible( true );
             return ( ImmediateComponentManager ) f.get( holder );
         }
@@ -194,11 +194,11 @@
     }
 
 
-    private static ImmediateComponentManager[] getComponentManagers( ConfiguredComponentHolder holder )
+    private static ImmediateComponentManager[] getComponentManagers( ImmediateComponentHolder holder )
     {
         try
         {
-            final Method m = ConfiguredComponentHolder.class.getDeclaredMethod( "getComponentManagers", new Class[]
+            final Method m = ImmediateComponentHolder.class.getDeclaredMethod( "getComponentManagers", new Class[]
                 { Boolean.TYPE } );
             m.setAccessible( true );
             return ( ImmediateComponentManager[] ) m.invoke( holder, new Object[]
@@ -211,7 +211,7 @@
         }
     }
 
-    private static class TestingConfiguredComponentHolder extends ConfiguredComponentHolder
+    private static class TestingConfiguredComponentHolder extends ImmediateComponentHolder
     {
         TestingConfiguredComponentHolder( ComponentMetadata metadata )
         {
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 1f59883..6878775 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
@@ -44,6 +44,7 @@
 import org.ops4j.pax.exam.OptionUtils;
 import org.ops4j.pax.exam.container.def.PaxRunnerOptions;
 import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.options.MavenArtifactUrlReference;
 import org.ops4j.pax.swissbox.tinybundles.core.TinyBundles;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -120,9 +121,9 @@
     @Before
     public void setUp() throws BundleException
     {
-        scrTracker = new ServiceTracker( bundleContext, ScrService.class.getName(), null );
+        scrTracker = new ServiceTracker( bundleContext, "org.apache.felix.scr.ScrService", null );
         scrTracker.open();
-        configAdminTracker = new ServiceTracker( bundleContext, ConfigurationAdmin.class.getName(), null );
+        configAdminTracker = new ServiceTracker( bundleContext, "org.osgi.service.cm.ConfigurationAdmin", null );
         configAdminTracker.open();
 
         bundle = installBundle( descriptorFile );