You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2015/07/09 00:10:16 UTC

svn commit: r1689973 [11/25] - in /felix/sandbox/pderop/dependencymanager.ds: cnf/ext/ cnf/localrepo/ cnf/localrepo/org.apache.felix.framework/ cnf/releaserepo/ org.apache.felix.dependencymanager.ds.itest/ org.apache.felix.dependencymanager.ds.itest/.s...

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrShellCommand.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrShellCommand.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrShellCommand.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrShellCommand.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,168 @@
+/*
+ * 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;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+import org.apache.felix.shell.Command;
+
+/**
+ * The <code>ScrShellCommand</code> implements command shell access for the
+ * legacy Apache Felix Shell. The actual implementation of the commands is
+ * found in the {@link ScrCommand} class.
+ */
+class ScrShellCommand implements Command
+{
+
+    private static final String HELP_CMD = "help";
+    private static final String LIST_CMD = "list";
+    private static final String INFO_CMD = "info";
+    private static final String ENABLE_CMD = "enable";
+    private static final String DISABLE_CMD = "disable";
+    private static final String CONFIG_CMD = "config";
+
+    private final ScrCommand scrCommand;
+
+    ScrShellCommand(final ScrCommand scrCommand)
+    {
+        this.scrCommand = scrCommand;
+    }
+
+    public String getName()
+    {
+        return "scr";
+    }
+
+    public String getUsage()
+    {
+        return "scr help";
+    }
+
+    public String getShortDescription()
+    {
+        return "Declarative Services Runtime";
+    }
+
+    public void execute(String commandLine, PrintStream out, PrintStream err)
+    {
+        // Parse the commandLine to get the OBR command.
+        String[] st = commandLine.split("\\s+");
+        // Ignore the invoking command.
+        // Try to get the OBR command, default is HELP command.
+        String command = st.length > 1? st[1]: HELP_CMD;
+        String arg = (st.length > 2) ? st[2] : null;
+
+        // Perform the specified command.
+        if (command.equals(HELP_CMD))
+        {
+            help(out, arg);
+        }
+        else
+        {
+            PrintWriter pw = new PrintWriter(out);
+            try
+            {
+                if (command.equals(LIST_CMD))
+                {
+                    scrCommand.list(arg, pw);
+                }
+                else if (command.equals(INFO_CMD))
+                {
+                    scrCommand.info(arg, pw);
+                }
+                else if (command.equals(ENABLE_CMD))
+                {
+                    scrCommand.change(arg, pw, true);
+                }
+                else if (command.equals(DISABLE_CMD))
+                {
+                    scrCommand.change(arg, pw, false);
+                }
+                else if (command.equals(CONFIG_CMD))
+                {
+                    scrCommand.config(pw);
+                }
+                else
+                {
+                    err.println("Unknown command: " + command);
+                }
+            }
+            catch ( IllegalArgumentException e )
+            {
+                System.err.println(e.getMessage());
+            }
+        }
+    }
+
+    private void help(PrintStream out, String command)
+    {
+        if (LIST_CMD.equals( command ))
+        {
+            out.println("");
+            out.println("scr " + LIST_CMD + " [ <bundleId> ]");
+            out.println("");
+            out.println("This command lists registered components. If a bundle ID is\n"
+                + "added, only the components of the selected bundles are listed.");
+            out.println("");
+        }
+        else if (INFO_CMD.equals( command ))
+        {
+            out.println("");
+            out.println("scr " + INFO_CMD + " <componentId>");
+            out.println("");
+            out.println("This command dumps information of the component whose\n"
+                + "component ID is given as command argument.");
+            out.println("");
+        }
+        else if (ENABLE_CMD.equals( command ))
+        {
+            out.println("");
+            out.println("scr " + ENABLE_CMD + " <componentId>");
+            out.println("");
+            out.println("This command enables the component whose component ID\n" + "is given as command argument.");
+            out.println("");
+        }
+        else if (DISABLE_CMD.equals( command ))
+        {
+            out.println("");
+            out.println("scr " + DISABLE_CMD + " <componentId>");
+            out.println("");
+            out.println("This command disables the component whose component ID\n" + "is given as command argument.");
+            out.println("");
+        }
+        else if (CONFIG_CMD.equals( command ))
+        {
+            out.println("");
+            out.println("scr " + CONFIG_CMD);
+            out.println("");
+            out.println("This command lists the current SCR configuration.");
+            out.println("");
+        }
+        else
+        {
+            out.println("scr " + HELP_CMD + " [" + LIST_CMD + "]");
+            out.println("scr " + LIST_CMD + " [ <bundleId> ]");
+            out.println("scr " + INFO_CMD + " <componentId>");
+            out.println("scr " + ENABLE_CMD + " <componentId>");
+            out.println("scr " + DISABLE_CMD + " <componentId>");
+            out.println("scr " + CONFIG_CMD);
+        }
+    }
+}

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/TargetedPID.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/TargetedPID.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/TargetedPID.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/TargetedPID.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,263 @@
+/*
+ * 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;
+
+import org.apache.felix.scr.impl.config.ComponentHolder;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+/**
+ * Copied with modifications from felix configadmin.
+ *
+ * The <code>TargetedPID</code> class represents a targeted PID as read
+ * from a configuration object.
+ * <p>
+ * For a factory configuration the <code>TargetedPID</code> represents
+ * the factory PID of the configuration. Otherwise it represents the
+ * PID itself of the configuration.
+ */
+public class TargetedPID
+{
+
+    private final String rawPid;
+
+    private final String servicePid;
+
+    private final String symbolicName;
+    private final String version;
+    private final String location;
+
+    /**
+     * The level of binding of this targeted PID:
+     * <ul>
+     * <li><code>0</code> -- this PID is not targeted at all</li>
+     * <li><code>1</code> -- this PID is targeted by the symbolic name</li>
+     * <li><code>2</code> -- this PID is targeted by the symbolic name and version</li>
+     * <li><code>3</code> -- this PID is targeted by the symbolic name, version, and location</li>
+     * </ul>
+     */
+    private final short bindingLevel;
+
+
+    /**
+     * Returns the bundle's version as required for targeted PIDs: If the
+     * bundle has a version the string representation of the version
+     * string converted to a Version object is returned. Otherwise the
+     * string representation of <code>Version.emptyVersion</code> is
+     * returned.
+     * <p>
+     * To remain compatible with pre-R4.2 (Framework API < 1.5) we cannot
+     * use the <code>Bundle.getVersion()</code> method.
+     *
+     * @param bundle The bundle whose version is to be returned.
+     */
+    public static String getBundleVersion( final Bundle bundle )
+    {
+        Object vHeader = bundle.getHeaders().get( Constants.BUNDLE_VERSION );
+        Version version = ( vHeader == null ) ? Version.emptyVersion : new Version( vHeader.toString() );
+        return version.toString();
+    }
+
+
+    public TargetedPID( final String rawPid )
+    {
+        this.rawPid = rawPid;
+
+        if ( rawPid.indexOf( '|' ) < 0 )
+        {
+            this.servicePid = rawPid;
+            this.symbolicName = null;
+            this.version = null;
+            this.location = null;
+            this.bindingLevel = 0;
+        }
+        else
+        {
+            int start = 0;
+            int end = rawPid.indexOf( '|' );
+            this.servicePid = rawPid.substring( start, end );
+
+            start = end + 1;
+            end = rawPid.indexOf( '|', start );
+            if ( end >= 0 )
+            {
+                this.symbolicName = rawPid.substring( start, end );
+                start = end + 1;
+                end = rawPid.indexOf( '|', start );
+                if ( end >= 0 )
+                {
+                    this.version = rawPid.substring( start, end );
+                    this.location = rawPid.substring( end + 1 );
+                    this.bindingLevel = 3;
+                }
+                else
+                {
+                    this.version = rawPid.substring( start );
+                    this.location = null;
+                    this.bindingLevel = 2;
+                }
+            }
+            else
+            {
+                this.symbolicName = rawPid.substring( start );
+                this.version = null;
+                this.location = null;
+                this.bindingLevel = 1;
+            }
+        }
+    }
+
+
+    /**
+     * Returns true if the target of this PID (bundle symbolic name,
+     * version, and location) match the bundle registering the referenced
+     * service.
+     * <p>
+     * This method just checks the target not the PID value itself, so
+     * this method returning <code>true</code> does not indicate whether
+     * the service actually is registered with a service PID equal to the
+     * raw PID of this targeted PID.
+     * <p>
+     * This method also returns <code>false</code> if the service has
+     * concurrently been unregistered and the registering bundle is now
+     * <code>null</code>.
+     *
+     * @param reference <code>ServiceReference</code> to the registered
+     *      service
+     * @return <code>true</code> if the referenced service matches the
+     *      target of this PID.
+     */
+    public boolean matchesTarget( ComponentHolder<?> holder )
+    {
+        // already unregistered
+        final Bundle serviceBundle = holder.getActivator().getBundleContext().getBundle();
+        if ( serviceBundle == null )
+        {
+            return false;
+        }
+
+        // This is not really targeted
+        if ( this.symbolicName == null )
+        {
+            return true;
+        }
+
+        // bundle symbolic names don't match
+        if ( !this.symbolicName.equals( serviceBundle.getSymbolicName() ) )
+        {
+            return false;
+        }
+
+        // no more specific target
+        if ( this.version == null )
+        {
+            return true;
+        }
+
+        // bundle version does not match
+
+        if ( !this.version.equals( getBundleVersion( serviceBundle ) ) )
+        {
+            return false;
+        }
+
+        // assert bundle location match
+        return this.location == null || this.location.equals( serviceBundle.getLocation() );
+    }
+
+
+    /**
+     * Gets the raw PID with which this instance has been created.
+     * <p>
+     * If an actual service PID contains pipe symbols that PID might be
+     * considered being targeted PID without it actually being one. This
+     * method provides access to the raw PID to allow for such services to
+     * be configured.
+     */
+    public String getRawPid()
+    {
+        return rawPid;
+    }
+
+
+    /**
+     * Returns the service PID of this targeted PID which basically is
+     * the targeted PID without the targeting information.
+     */
+    public String getServicePid()
+    {
+        return servicePid;
+    }
+
+
+    /**
+     * Returns <code>true</code> if this targeted PID binds stronger than
+     * the <code>other</code> {@link TargetedPID}.
+     * <p>
+     * This method assumes both targeted PIDs have already been checked for
+     * suitability for the bundle encoded in the targetting.
+     *
+     * @param other The targeted PID to check whether it is binding stronger
+     *      or not.
+     * @return <code>true</code> if the <code>other</code> targeted PID
+     *      is binding strong.
+     */
+    public boolean bindsStronger( final TargetedPID other )
+    {
+        return other == null || this.bindingLevel > other.bindingLevel;
+    }
+
+
+    @Override
+    public int hashCode()
+    {
+        return this.rawPid.hashCode();
+    }
+
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == null )
+        {
+            return false;
+        }
+        else if ( obj == this )
+        {
+            return true;
+        }
+
+        // assume equality if same class and raw PID equals
+        if ( this.getClass() == obj.getClass() )
+        {
+            return this.rawPid.equals( ( ( TargetedPID ) obj ).rawPid );
+        }
+
+        // not the same class or different raw PID
+        return false;
+    }
+
+
+    @Override
+    public String toString()
+    {
+        return this.rawPid;
+    }
+}

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentContainer.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentContainer.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentContainer.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentContainer.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,46 @@
+/*
+ * 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.SingleComponentManager;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+
+public interface ComponentContainer<S>
+{
+
+    /**
+     * Returns the {@link BundleComponentActivator} owning this component
+     * holder.  (overlaps ComponentHolder)
+     */
+    BundleComponentActivator getActivator();
+
+    /**
+     * Returns the {@link ComponentMetadata} describing and declaring this
+     * component. (overlaps ComponentHolder)
+     */
+    ComponentMetadata getComponentMetadata();
+
+    /**
+     * Informs the holder that the component has been disposed as a result of
+     * calling the dispose method.
+     */
+    void disposed(SingleComponentManager<S> component);
+
+}
\ No newline at end of file

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentHolder.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentHolder.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentHolder.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentHolder.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,129 @@
+/*
+ * 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 java.util.List;
+
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.TargetedPID;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+import org.osgi.util.promise.Promise;
+
+
+/**
+ * The <code>ComponentHolder</code> interface provides the API for supporting
+ * component instances configured through either singleton configurations (or
+ * no configuration at all) and factory configurations.
+ * <p>
+ * Instances of this interface are managed by the {@link ConfigurationSupport}
+ * class on behalf of the
+ * {@link org.apache.felix.scr.impl.BundleComponentActivator} and the
+ * {@link org.apache.felix.scr.impl.ComponentRegistry}.
+ */
+public interface ComponentHolder<S>
+{
+
+    /**
+     * Returns the {@link BundleComponentActivator} owning this component
+     * holder. (overlaps ComponentContaienr)
+     */
+    BundleComponentActivator getActivator();
+
+    /**
+     * Returns the {@link ComponentMetadata} describing and declaring this
+     * component. (overlaps ComponentContaienr)
+     */
+    ComponentMetadata getComponentMetadata();
+
+    /**
+     * The configuration with the given PID has been deleted from the
+     * Configuration Admin service.
+     *
+     * @param pid The PID of the deleted configuration
+     * @param factoryPid The factory PID of the deleted configuration
+     */
+    void configurationDeleted( TargetedPID pid, TargetedPID factoryPid );
+
+
+    /**
+     * Configure a component with configuration from the given PID.
+     * @param targetedPid Targeted PID for the configuration
+     * @param factoryTargetedPid the (targeted) factory pid or null for a singleton pid
+     * @param props the property dictionary from the configuration.
+     * @param changeCount change count of the configuration, or R4 imitation.
+     *
+     * @return true if a new component is created for a factory PID, false if an existing factory pid configuration is updated or 
+     * we have no factory pid
+     */
+    boolean configurationUpdated( TargetedPID targetedPid, TargetedPID factoryTargetedPid, Dictionary<String, Object> props, long changeCount );
+    
+    /**
+     * Change count (or fake R4 imitation)
+     * @param pid a PID for the component we are interested in.
+     * @param targetedPid For a singleton pid, same as "pid"; for a factory pid, the factory pid.
+     * @return the last change count from a configurationUpdated call for the given pid.
+     */
+    long getChangeCount( TargetedPID pid, TargetedPID targetedPid );
+    
+    /**
+     * Returns the targeted PID used to configure this component
+     * @param pid a targetedPID containing the service pid for the component desired (the rest of the targeted pid is ignored)
+     * @param factoryPid a targetedPID containing the factory pid for the component desired.
+     * @return the complete targeted pid actually used to configure the comonent.
+     */
+    TargetedPID getConfigurationTargetedPID(TargetedPID pid, TargetedPID factoryPid);
+
+    /**
+     * Returns all <code>Component</code> instances held by this holder.
+     */
+    List<? extends ComponentManager<?>> getComponents();
+
+    /**
+     * Enables all components of this holder and if satisfied activates
+     * them.
+     *
+     * @param async Whether the actual activation should take place
+     *      asynchronously or not.
+     */
+    Promise<Void> enableComponents( boolean async );
+
+
+    /**
+     * Disables all components of this holder.
+     *
+     * @param async Whether the actual deactivation should take place
+     *      asynchronously or not.
+     */
+    Promise<Void> disableComponents( boolean async );
+    
+    /**
+     * whether the component is currently enabled
+     * @return whether the component is enabled
+     */
+    boolean isEnabled();
+
+
+    /**
+     * Disposes off all components of this holder.
+     * @param reason
+     */
+    void disposeComponents( int reason );
+}

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentManager.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentManager.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentManager.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ComponentManager.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,44 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
+
+
+public interface ComponentManager<S> {
+	
+    int STATE_UNSATISFIED_CONFIGURATION = ComponentConfigurationDTO.UNSATISFIED_CONFIGURATION;
+    int STATE_UNSATISFIED_REFERENCE = ComponentConfigurationDTO.UNSATISFIED_REFERENCE;
+    int STATE_SATISFIED = ComponentConfigurationDTO.SATISFIED;
+	int STATE_ACTIVE = ComponentConfigurationDTO.ACTIVE;
+	int STATE_DISPOSED = 32;
+	int STATE_DISABLED = 64; //TODO????
+
+	Map<String, Object> getProperties();
+
+	long getId();
+
+	int getState();
+	
+	List<? extends ReferenceManager<S, ?>> getReferenceManagers();
+	
+}
\ No newline at end of file

Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java?rev=1689973&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java (added)
+++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/config/ConfigurableComponentHolder.java Wed Jul  8 22:10:14 2015
@@ -0,0 +1,882 @@
+/*
+ * 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.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.scr.impl.Activator;
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.TargetedPID;
+import org.apache.felix.scr.impl.helper.ComponentMethods;
+import org.apache.felix.scr.impl.helper.SimpleLogger;
+import org.apache.felix.scr.impl.manager.AbstractComponentManager;
+import org.apache.felix.scr.impl.manager.ComponentFactoryImpl;
+import org.apache.felix.scr.impl.manager.PrototypeServiceFactoryComponentManager;
+import org.apache.felix.scr.impl.manager.ServiceFactoryComponentManager;
+import org.apache.felix.scr.impl.manager.SingleComponentManager;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+import org.apache.felix.scr.impl.metadata.ServiceMetadata.Scope;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.log.LogService;
+import org.osgi.util.promise.Deferred;
+import org.osgi.util.promise.Promise;
+import org.osgi.util.promise.Promises;
+
+
+/**
+ * The <code>ConfigurableComponentHolder</code> class is a
+ * {@link ComponentHolder} for automatically configured components instances
+ * that may or may not be configured through Config Admin.
+ * <p>
+ * The holder copes with three situations:
+ * <ul>
+ * <li>No configuration is available for the held component. That is there is
+ * no configuration whose <code>service.pid</code> or
+ * <code>service.factoryPid</code> equals the component name.</li>
+ * <li>A singleton configuration is available whose <code>service.pid</code>
+ * equals the component name.</li>
+ * <li>One or more factory configurations exist whose
+ * <code>service.factoryPid</code> equals the component name.</li>
+ * </ul>
+ */
+public class ConfigurableComponentHolder<S> implements ComponentHolder<S>, ComponentContainer<S>, SimpleLogger
+{
+
+    /**
+     * 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;
+
+    /** the targeted pids corresponding to the pids specified in the config metadata, except possibly for the single
+     * factory pid
+     */
+    private final TargetedPID[] m_targetedPids;
+
+    private final Long[] m_changeCount;
+
+    private final Map<String, Long> m_factoryChangeCount = new HashMap<String, Long>();
+
+    /**
+     * the index in metadata.getConfigurationPid() of the base factory pid, if any.  Each component created from a factory configuration
+     * might have a different targeted pid.
+     */
+    private Integer m_factoryPidIndex;
+
+    /**
+     * the non-factory configurations shared between all instances.
+     */
+    private final Dictionary<String, Object>[] m_configurations;
+
+    /**
+     * the factory configurations indexed by pid (which cannot be a TargetedPID since it's generated by CA).  We have to track these since
+     * other required configs may not yet be present so we can't create the component manager yet.
+     */
+    private final Map<String, Dictionary<String, Object>> m_factoryConfigurations = new HashMap<String, Dictionary<String, Object>>();
+
+    /**
+     * Each factory config may be from a different TargetedPID (sharing the same base service pid, but with different level of detail)
+     */
+    private final Map<String, TargetedPID> m_factoryTargetedPids = new HashMap<String, TargetedPID>();
+    /**
+     * 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 SingleComponentManager<S> component instances}
+     * created on behalf of the configurations.
+     */
+    private final Map<String, AbstractComponentManager<S>> m_components;
+
+    /**
+     * The special component used if there is no configuration or a singleton
+     * configuration. This field is only <code>null</code> once all components
+     * held by this holder have been disposed of by
+     * {@link #disposeComponents(int)} and is first created in the constructor.
+     * As factory configurations are provided this instance may be configured
+     * or "deconfigured".
+     * <p>
+     * Expected invariants:
+     * <ul>
+     * <li>This field is only <code>null</code> after disposal of all held
+     * components</li>
+     * <li>The {@link #m_components} map is empty or the component pointed to
+     * by this field is also contained in the map</li>
+     * <ul>
+     */
+    private AbstractComponentManager<S> m_singleComponent;
+
+    /**
+     * Whether components have already been enabled by calling the
+     * {@link #enableComponents(boolean)} method. If this field is <code>true</code>
+     * component instances created per configuration by the
+     * {@link #configurationUpdated(TargetedPID, TargetedPID, Dictionary, long)} method are also
+     * enabled. Otherwise they are not enabled immediately.
+     */
+    private volatile boolean m_enabled;
+    private final Object enableLock = new Object();
+    private Promise<Void> m_enablePromise;
+    private Promise<Void> m_disablePromise = Promises.resolved(null);
+
+    private final ComponentMethods m_componentMethods;
+
+    public ConfigurableComponentHolder( final BundleComponentActivator activator, final ComponentMetadata metadata )
+    {
+        this.m_activator = activator;
+        this.m_componentMetadata = metadata;
+        int pidCount = metadata.getConfigurationPid().size();
+        this.m_targetedPids = new TargetedPID[pidCount];
+        this.m_configurations = new Dictionary[pidCount];
+        this.m_changeCount = new Long[pidCount];
+        this.m_components = new HashMap<String, AbstractComponentManager<S>>();
+        this.m_componentMethods = new ComponentMethods();
+        this.m_enabled = false;
+    }
+
+    protected AbstractComponentManager<S> createComponentManager(boolean factoryConfiguration)
+    {
+
+        AbstractComponentManager<S> manager;
+        if ( m_componentMetadata.isFactory() )
+        {
+            //TODO is there any check to make sure factory component factories are enabled before creating them?
+            if ( !m_componentMetadata.isObsoleteFactoryComponentFactory() || !factoryConfiguration )
+            {
+                manager = new ComponentFactoryImpl<S>(this );
+            }
+            else
+            {
+                manager = new SingleComponentManager<S>(this, m_componentMethods, true );
+            }
+        }
+        else if ( m_componentMetadata.getServiceScope() == Scope.bundle )
+        {
+            manager = new ServiceFactoryComponentManager<S>( this, m_componentMethods );
+        }
+
+        else if ( m_componentMetadata.getServiceScope() == Scope.prototype )
+        {
+            manager = PSFLoader.newPSFComponentManager(this, m_componentMethods);
+        }
+
+        else
+        {
+            //immediate or delayed
+            manager = new SingleComponentManager<S>( this, m_componentMethods );
+        }
+
+        return manager;
+    }
+
+    private static class PSFLoader
+    {
+        static <S> AbstractComponentManager<S> newPSFComponentManager(ConfigurableComponentHolder<S> holder, ComponentMethods methods)
+        {
+            return new PrototypeServiceFactoryComponentManager<S>( holder, methods );
+        }
+    }
+
+
+    public final BundleComponentActivator getActivator()
+    {
+        return m_activator;
+    }
+
+
+    public final ComponentMetadata getComponentMetadata()
+    {
+        return m_componentMetadata;
+    }
+
+
+    /**
+     * The configuration with the given <code>pid</code>
+     * (<code>service.pid</code> of the configuration object) is deleted.
+     * <p>
+     * The following situations are supported:
+     * <ul>
+     * <li>The configuration was a singleton configuration (pid equals the
+     * component name). In this case the internal component map is empty and
+     * the single component has been configured by the singleton configuration
+     * and is no "deconfigured".</li>
+     * <li>A factory configuration object has been deleted and the configured
+     * object is set as the single component. If the single component held the
+     * last factory configuration object, it is deconfigured. Otherwise the
+     * single component is disposed off and replaced by another component in
+     * the map of existing components.</li>
+     * <li>A factory configuration object has been deleted and the configured
+     * object is not set as the single component. In this case the component is
+     * simply disposed off and removed from the internal map.</li>
+     * </ul>
+     */
+    public void configurationDeleted( final TargetedPID pid, TargetedPID factoryPid )
+    {
+        log( LogService.LOG_DEBUG, "ImmediateComponentHolder configuration deleted for pid {0}",
+            new Object[] {pid}, null);
+
+        // component to deconfigure or dispose of
+        final Map<AbstractComponentManager<S>, Map<String, Object>> scms = new HashMap<AbstractComponentManager<S>, Map<String, Object>>();
+        boolean reconfigure = false;
+
+        synchronized ( m_components )
+        {
+            if (factoryPid != null) {
+                checkFactoryPidIndex(factoryPid);
+                String servicePid = pid.getServicePid();
+                m_factoryTargetedPids.remove(servicePid);
+                m_factoryChangeCount.remove(servicePid);
+                m_factoryConfigurations.remove(servicePid);
+                AbstractComponentManager<S> scm = m_components.remove(servicePid);
+                if ( m_factoryConfigurations.isEmpty() )
+                {
+                    m_factoryPidIndex = null;
+                }
+                if ( !m_enabled || scm == null )
+                {
+                    return;
+                }
+                reconfigure = m_componentMetadata.isConfigurationOptional() && m_components.isEmpty();
+                if ( reconfigure )
+                {
+                    m_singleComponent = scm;
+                    scms.put( scm, mergeProperties(null) );
+                }
+                else
+                {
+                    scms.put( scm,  null );
+                }
+            }
+            else
+            {
+                //singleton pid
+                int index = getSingletonPidIndex(pid);
+                m_targetedPids[index] = null;
+                m_changeCount[index] = null;
+                m_configurations[index] = null;
+                if ( !m_enabled )
+                {
+                    return;
+                }
+                reconfigure = m_componentMetadata.isConfigurationOptional();
+
+                if ( m_factoryPidIndex == null)
+                {
+                    if ( m_singleComponent != null ) {
+                        if (reconfigure) {
+                            scms.put(m_singleComponent, mergeProperties(null));
+                        } else {
+                            scms.put(m_singleComponent, null);
+                            m_singleComponent = null;
+                        }
+                    }
+                }
+                else
+                {
+                    if (reconfigure) {
+                        for (Map.Entry<String, AbstractComponentManager<S>> entry : m_components.entrySet()) {
+                            scms.put(entry.getValue(), mergeProperties(entry.getKey()));
+                        }
+                    }
+                    else
+                    {
+                        for (Map.Entry<String, AbstractComponentManager<S>> entry : m_components.entrySet()) {
+                            scms.put(entry.getValue(), null );
+                        }
+                        m_components.clear();
+                    }
+                }
+
+            }
+        }
+
+        for ( Map.Entry<AbstractComponentManager<S>,Map<String, Object>> entry: scms.entrySet())
+        {
+            if ( reconfigure ) {
+                entry.getKey().reconfigure( entry.getValue(), true);
+            } else {
+                entry.getKey().dispose(ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED);
+            }
+        }
+    }
+
+
+    /**
+     * Configures a component with the given configuration. This configuration
+     * update may happen in various situations:
+     * <ul>
+     * <li>The <code>pid</code> equals the component name. Hence we have a
+     * singleton configuration for the single component held by this holder</li>
+     * <li>The configuration is a factory configuration and is the first
+     * configuration provided. In this case the single component is provided
+     * with the configuration and also stored in the map.</li>
+     * <li>The configuration is a factory configuration but not the first. In
+     * this case a new component is created, configured and stored in the map</li>
+     * </ul>
+     * @return true if a new configuration was created, false otherwise. //TODO there are now 3 states..... still not satisfied, existing, and new
+     */
+    public boolean configurationUpdated( TargetedPID pid, TargetedPID factoryPid, final Dictionary<String, Object> props, long changeCount )
+    {
+        log( LogService.LOG_DEBUG, "ConfigurableComponentHolder configuration updated for pid {0} with properties {1}",
+            new Object[] {pid, props}, null);
+
+        // component to update or create
+        final Map<AbstractComponentManager<S>, Map<String, Object>> scms = new HashMap< AbstractComponentManager<S>, Map<String, Object>>();
+        boolean created = false;
+
+        //TODO better change count tracking
+        synchronized (m_components) {
+            //Find or create the component manager, or return if not satisfied.
+            if (factoryPid != null) {
+                checkFactoryPidIndex(factoryPid);
+                m_factoryConfigurations.put(pid.getServicePid(), props);
+                m_factoryTargetedPids.put(pid.getServicePid(), factoryPid);
+                m_factoryChangeCount.put(pid.getServicePid(), changeCount);
+                if (m_enabled && isSatisfied()) {
+                    if (m_singleComponent != null && !m_componentMetadata.isObsoleteFactoryComponentFactory()) {
+                        AbstractComponentManager<S> scm = m_singleComponent;
+                        scms.put( scm, mergeProperties( pid.getServicePid() ) );
+                        m_singleComponent = null;
+                        m_components.put(pid.getServicePid(), scm);
+                    } else if (m_components.containsKey(pid.getServicePid())) {
+                        scms.put( m_components.get(pid.getServicePid()), mergeProperties( pid.getServicePid())  );
+                    } else {
+                        AbstractComponentManager<S> scm = createComponentManager(true);
+                        m_components.put(pid.getServicePid(), scm);
+                        scms.put( scm, mergeProperties( pid.getServicePid())  );
+                        created = true;
+                    }
+                } else {
+                    return false;
+                }
+
+            } else {
+                //singleton pid
+                int index = getSingletonPidIndex(pid);
+                m_targetedPids[index] = pid;
+                m_changeCount[index] = changeCount;
+                m_configurations[index] = props;
+                if (m_enabled && isSatisfied()) {
+                    if (m_singleComponent != null) {
+                        scms.put( m_singleComponent, mergeProperties( pid.getServicePid() ) );
+                    }
+                    else if ( m_factoryPidIndex != null)
+                    {
+                        for (Map.Entry<String, AbstractComponentManager<S>> entry: m_components.entrySet())
+                        {
+                            scms.put(entry.getValue(), mergeProperties( entry.getKey()));
+                        }
+                    }
+                    else
+                    {
+                        m_singleComponent = createComponentManager(false);
+                        scms.put( m_singleComponent, mergeProperties( pid.getServicePid() ) );
+                        created = true;
+                    }
+                } else {
+                    return false;
+                }
+
+            }
+
+        }
+
+
+        // we have the icm.
+        //properties is all the configs merged together (without any possible component factory info.
+
+        final boolean enable = created && m_enabled;// TODO WTF?? && getComponentMetadata().isEnabled();
+        for ( Map.Entry<AbstractComponentManager<S>,Map<String, Object>> entry: scms.entrySet())
+        {
+            // configure the component
+            entry.getKey().reconfigure(entry.getValue(), false);
+            log(LogService.LOG_DEBUG,
+                "ImmediateComponentHolder Finished configuring the dependency managers for component for pid {0} ",
+                new Object[] { pid }, null);
+            if (enable) {
+                entry.getKey().enable(false);
+                log(LogService.LOG_DEBUG,
+                    "ImmediateComponentHolder Finished enabling component for pid {0} ",
+                    new Object[] { pid }, null);
+            } else {
+                log(LogService.LOG_DEBUG,
+                    "ImmediateComponentHolder Will not enable component for pid {0}: holder enabled state: {1}, metadata enabled: {2} ",
+                    new Object[] { pid, m_enabled,
+                    m_componentMetadata.isEnabled() }, null);
+            }
+        }
+        return created;
+    }
+
+    private Map<String, Object> mergeProperties(String servicePid) {
+        Map<String, Object> properties = new HashMap<String, Object>(m_componentMetadata.getProperties());
+        List<String> pids = null;
+        boolean isDS13 = m_componentMetadata.getDSVersion().isDS13();
+        if (isDS13)
+        {
+            pids = new ArrayList<String>();
+            if (properties.get(Constants.SERVICE_PID) instanceof String)
+            {
+                pids.add((String) properties.get(Constants.SERVICE_PID));
+            }
+        }
+        for (int i = 0; i < m_configurations.length; i++)
+        {
+            if ( m_factoryPidIndex != null && i == m_factoryPidIndex
+                && !( m_componentMetadata.isObsoleteFactoryComponentFactory() && servicePid == null)) //obsolete special case
+            {
+                copyTo(properties, m_factoryConfigurations.get(servicePid));
+                if (isDS13)
+                {
+                    pids.add((String) m_factoryConfigurations.get(servicePid).get(Constants.SERVICE_PID));
+                }
+            }
+            else if ( m_configurations[i] != null )
+            {
+                copyTo(properties, m_configurations[i]);
+                if (isDS13)
+                {
+                    pids.add((String) m_configurations[i].get(Constants.SERVICE_PID));
+                }
+            }
+        }
+        if (isDS13 && !pids.isEmpty())
+        {
+        	if ( pids.size() == 1 )
+        	{
+        		properties.put(Constants.SERVICE_PID, pids.get(0));
+        	}
+        	else
+        	{
+        		properties.put(Constants.SERVICE_PID, pids);
+        	}
+        }
+        return properties;
+    }
+
+    private int getSingletonPidIndex(TargetedPID pid) {
+        int index = m_componentMetadata.getPidIndex(pid);
+        if (index == -1) {
+            log(LogService.LOG_ERROR,
+                "Unrecognized pid {0}, expected one of {1}",
+                new Object[] { pid,
+                m_componentMetadata.getConfigurationPid() },
+                null);
+            throw new IllegalArgumentException("Unrecognized pid "
+                + pid);
+        }
+        if (m_factoryPidIndex != null && index == m_factoryPidIndex) {
+            log(LogService.LOG_ERROR,
+                "singleton pid {0} supplied, but matches an existing factory pid at index: {1}",
+                new Object[] { pid, m_factoryPidIndex }, null);
+            throw new IllegalStateException(
+                "Singleton pid supplied matching a previous factory pid "
+                    + pid);
+        }
+        return index;
+    }
+
+    //TODO update error messages so they make sense for deleting config too.
+    private void checkFactoryPidIndex(TargetedPID factoryPid) {
+        int index = m_componentMetadata.getPidIndex(factoryPid);
+        if (index == -1) {
+            log(LogService.LOG_ERROR,
+                "Unrecognized factory pid {0}, expected one of {1}",
+                new Object[] { factoryPid,
+                m_componentMetadata.getConfigurationPid() },
+                null);
+            throw new IllegalArgumentException(
+                "Unrecognized factory pid " + factoryPid);
+        }
+        if (m_configurations[index] != null) {
+            log(LogService.LOG_ERROR,
+                "factory pid {0}, but this pid is already supplied as a singleton: {1} at index {2}",
+                new Object[] { factoryPid, Arrays.asList(m_targetedPids), index }, null);
+            throw new IllegalStateException(
+                "Factory pid supplied after all non-factory configurations supplied "
+                    + factoryPid);
+        }
+        if (m_factoryPidIndex == null) {
+            m_factoryPidIndex = index;
+        } else if (index != m_factoryPidIndex) {
+            log(LogService.LOG_ERROR,
+                "factory pid {0} supplied for index {1}, but a factory pid previously supplied at index {2}",
+                new Object[] { factoryPid, index, m_factoryPidIndex },
+                null);
+            throw new IllegalStateException(
+                "Factory pid supplied at wrong index " + factoryPid);
+        }
+    }
+
+    protected static void copyTo( Map<String, Object> target, Dictionary<String, ?> source )
+    {
+
+        for ( Enumeration<String> keys = source.keys(); keys.hasMoreElements(); )
+        {
+            String key = keys.nextElement();
+            Object value = source.get(key);
+            target.put(key, value);
+        }
+    }
+
+    /**
+     * Determine if the holder is satisfied with configurations
+     * @return true if configuration optional or all pids supplied with configurations
+     */
+    private boolean isSatisfied() {
+        if ( m_componentMetadata.isConfigurationOptional() || m_componentMetadata.isConfigurationIgnored() )
+        {
+            return true;
+        }
+        for ( int i = 0; i < m_componentMetadata.getConfigurationPid().size(); i++)
+        {
+            if ( m_configurations[i] != null)
+            {
+                continue;
+            }
+            if ( m_factoryPidIndex != null && m_factoryPidIndex == i)
+            {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * @param pid the Targeted PID we need the change count for
+     * @param targetedPid the targeted factory pid for a factory configuration or the pid for a singleton configuration
+     * @return pid for this service pid.
+     */
+    public long getChangeCount( TargetedPID pid, TargetedPID targetedPid)
+    {
+        int index = m_componentMetadata.getPidIndex(targetedPid);
+        Long result;
+        if ( index == -1 )
+        {
+            throw new IllegalArgumentException("pid not recognized as for this component: " + pid);
+        }
+        if ( m_factoryPidIndex != null && index == m_factoryPidIndex )
+        {
+            result = m_factoryChangeCount.get(pid.getServicePid());
+        }
+        else
+        {
+            result = m_changeCount[index];
+        }
+        return result == null? -1: result;
+
+    }
+
+    public List<? extends ComponentManager<?>> getComponents()
+        {
+        synchronized ( m_components )
+        {
+            return getComponentManagers( );
+        }
+        }
+
+
+    public boolean isEnabled() {
+        return m_enabled;
+    }
+
+
+    private void wait(Promise<Void> promise)
+    {
+        boolean waited = false;
+        boolean interrupted = false;
+        while ( !waited )
+        {
+            try
+            {
+                promise.getValue();
+                waited = true;
+            }
+            catch ( InterruptedException e )
+            {
+                interrupted = true;
+            }
+            catch (InvocationTargetException e)
+            {
+                //this is not going to happen
+            }
+        }
+        if ( interrupted )
+        {
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    public Promise<Void> enableComponents( final boolean async )
+    {
+        synchronized (enableLock)
+        {
+            if ( m_enablePromise != null)
+            {
+                return m_enablePromise;
+            }
+            wait( m_disablePromise );
+
+
+            List<AbstractComponentManager<S>> cms = new ArrayList<AbstractComponentManager<S>>();
+            synchronized ( m_components )
+            {
+                if ( isSatisfied() )
+                {
+                    if ( m_factoryPidIndex == null ||
+                            (m_componentMetadata.isObsoleteFactoryComponentFactory() && !m_componentMetadata.isConfigurationRequired()))
+                    {
+                        m_singleComponent = createComponentManager(false);
+                        cms.add( m_singleComponent );
+                        m_singleComponent.reconfigure(mergeProperties( null ), false);
+                    }
+                    if ( m_factoryPidIndex != null)
+                    {
+                        for (String pid: m_factoryConfigurations.keySet()) {
+                            AbstractComponentManager<S> scm = createComponentManager(true);
+                            m_components.put(pid, scm);
+                            scm.reconfigure( mergeProperties( pid ), false);
+                            cms.add( scm );
+                        }
+                    }
+                }
+                m_enabled = true;
+            }
+            List<Promise<Void>> promises = new ArrayList<Promise<Void>>();
+            for ( AbstractComponentManager<S> cm : cms )
+            {
+                promises.add(cm.enable( async ));
+            }
+            m_enablePromise = new Deferred<List<Void>>().resolveWith(Promises.<Void, Void>all(promises));
+            m_disablePromise = null;
+            return m_enablePromise;
+        }
+    }
+
+
+    public Promise<Void> disableComponents( final boolean async )
+    {
+        synchronized (enableLock)
+        {
+            if ( m_disablePromise != null)
+            {
+                return m_disablePromise;
+            }
+            wait( m_enablePromise );
+
+            List<AbstractComponentManager<S>> cms;
+            synchronized ( m_components )
+            {
+                m_enabled = false;
+
+                cms = getDirectComponentManagers( );
+                clearComponents();
+            }
+            List<Promise<Void>> promises = new ArrayList<Promise<Void>>();
+            for ( AbstractComponentManager<S> cm : cms )
+            {
+                promises.add(cm.disable( async ));
+            }
+            m_disablePromise = new Deferred<List<Void>>().resolveWith(Promises.<Void, Void>all(promises));
+            m_enablePromise = null;
+            return m_disablePromise;
+        }
+    }
+
+
+    public void disposeComponents( final int reason )
+    {
+        List<AbstractComponentManager<S>> cms;
+        synchronized ( m_components )
+        {
+            cms = getDirectComponentManagers( );
+            clearComponents();
+        }
+        for ( AbstractComponentManager<S> cm : cms )
+        {
+            cm.dispose( reason );
+        }
+    }
+
+
+    public void disposed( SingleComponentManager<S> component )
+    {
+        // ensure the component is removed from the components map
+        synchronized ( m_components )
+        {
+            if ( !m_components.isEmpty() )
+            {
+                for ( Iterator<AbstractComponentManager<S>> vi = m_components.values().iterator(); vi.hasNext(); )
+                {
+                    if ( component == vi.next() )
+                    {
+                        vi.remove();
+                        break;
+                    }
+                }
+            }
+
+            if ( component == m_singleComponent )
+            {
+                m_singleComponent = null;
+            }
+        }
+    }
+
+    /**
+     * Compares this {@code ImmediateComponentHolder} object to another object.
+     *
+     * <p>
+     * A ImmediateComponentHolder is considered to be <b>equal to </b> another
+     * ImmediateComponentHolder if the component names are equal(using
+     * {@code String.equals}) and they have the same bundle activator
+     *
+     * @param object The {@code ImmediateComponentHolder} object to be compared.
+     * @return {@code true} if {@code object} is a
+     *         {@code ImmediateComponentHolder} and is equal to this object;
+     *         {@code false} otherwise.
+     */
+    @Override
+    public boolean equals(Object object)
+    {
+        if (!(object instanceof ConfigurableComponentHolder))
+        {
+            return false;
+        }
+
+        ConfigurableComponentHolder<S> other = (ConfigurableComponentHolder<S>) object;
+        return m_activator == other.m_activator
+            && getName().equals(other.getName());
+    }
+
+    /**
+     * Returns a hash code value for the object.
+     *
+     * @return An integer which is a hash code value for this object.
+     */
+    @Override
+    public int hashCode()
+    {
+        return getName().hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "[ImmediateComponentHolder:" + getName() + "]";
+    }
+
+    String getName()
+    {
+        return m_componentMetadata.getName();
+    }
+
+    //---------- internal
+
+    /**
+     * Returns all component managers from the map and the single component manager, optionally also removing them
+     * from the map. If there are no component managers, <code>null</code>
+     * is returned.  Must be called synchronized on m_components.
+     */
+    List<AbstractComponentManager<S>> getComponentManagers( )
+    {
+        List<AbstractComponentManager<S>> cms = new ArrayList<AbstractComponentManager<S>>();
+        if ( m_singleComponent != null)
+        {
+            m_singleComponent.getComponentManagers(cms);
+        }
+
+        for (AbstractComponentManager<S> cm: m_components.values())
+        {
+            cm.getComponentManagers(cms);
+        }
+        return cms;
+    }
+
+    List<AbstractComponentManager<S>> getDirectComponentManagers( )
+    {
+        List<AbstractComponentManager<S>> cms = new ArrayList<AbstractComponentManager<S>>();
+        if ( m_singleComponent != null)
+        {
+            cms.add(m_singleComponent);
+        }
+        cms.addAll(m_components.values());
+        return cms;
+    }
+
+    void clearComponents()
+    {
+        m_components.clear();
+        m_singleComponent = null;
+    }
+
+    public boolean isLogEnabled( int level )
+    {
+        return Activator.isLogEnabled( level );
+    }
+
+    public void log( int level, String message, Throwable ex )
+    {
+        BundleComponentActivator activator = getActivator();
+        if ( activator != null )
+        {
+            activator.log( level, message, getComponentMetadata(), null, ex );
+        }
+    }
+
+    public void log( int level, String message, Object[] arguments, Throwable ex )
+    {
+        BundleComponentActivator activator = getActivator();
+        if ( activator != null )
+        {
+            activator.log( level, message, arguments, getComponentMetadata(), null, ex );
+        }
+    }
+
+    public TargetedPID getConfigurationTargetedPID(TargetedPID pid, TargetedPID factoryPid)
+    {
+        if ( factoryPid == null )
+        {
+            int index = m_componentMetadata.getPidIndex(pid);
+            if (index != -1)
+            {
+                return m_targetedPids[index];
+            }
+            return null;
+        }
+        //each factory configured component may have a different factory targeted pid.
+        synchronized (m_components)
+        {
+            return m_factoryTargetedPids.get(pid.getServicePid());
+        }
+    }
+
+}