Added: 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/BundleComponentActivator.java
URL: 
http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/BundleComponentActivator.java?rev=1689973&view=auto
==============================================================================
--- 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/BundleComponentActivator.java
 (added)
+++ 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/BundleComponentActivator.java
 Wed Jul  8 22:10:14 2015
@@ -0,0 +1,659 @@
+/*
+ * 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.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.felix.scr.impl.config.ComponentHolder;
+import org.apache.felix.scr.impl.config.ScrConfiguration;
+import org.apache.felix.scr.impl.helper.Logger;
+import org.apache.felix.scr.impl.manager.AbstractComponentManager;
+import org.apache.felix.scr.impl.manager.DependencyManager;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+import org.apache.felix.scr.impl.metadata.XmlHandler;
+import org.apache.felix.scr.impl.parser.KXml2SAXParser;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentException;
+import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.ServiceTracker;
+
+
+/**
+ * The BundleComponentActivator is helper class to load and unload Components 
of
+ * a single bundle. It will read information from the metadata.xml file
+ * descriptors and create the corresponding managers.
+ */
+public class BundleComponentActivator implements Logger
+{
+    // global component registration
+    private final ComponentRegistry m_componentRegistry;
+
+    // The bundle owning the registered component
+    private final Bundle m_bundle;
+
+    // The bundle context owning the registered component
+    private final BundleContext m_context;
+
+    // This is a list of component instance managers that belong to a 
particular bundle
+    private final List<ComponentHolder<?>> m_managers = new 
ArrayList<ComponentHolder<?>>();
+
+    // The Configuration Admin tracker providing configuration for components
+    private final ServiceTracker<LogService, LogService> m_logService;
+
+    // thread acting upon configurations
+    private final ComponentActorThread m_componentActor;
+
+    // true as long as the dispose method is not called
+    private final AtomicBoolean m_active = new AtomicBoolean(true);
+    private final CountDownLatch m_closeLatch = new CountDownLatch(1);
+
+    // the configuration
+    private final ScrConfiguration m_configuration;
+
+
+    /**
+     * Called upon starting of the bundle. This method invokes initialize() 
which
+     * parses the metadata and creates the instance managers
+     *
+     * @param componentRegistry The <code>ComponentRegistry</code> used to
+     *      register components with to ensure uniqueness of component names
+     *      and to ensure configuration updates.
+     * @param   context  The bundle context owning the components
+     *
+     * @throws ComponentException if any error occurrs initializing this class
+     */
+    BundleComponentActivator( ComponentRegistry componentRegistry,
+        ComponentActorThread componentActor, BundleContext context, 
ScrConfiguration configuration ) throws ComponentException
+    {
+        // keep the parameters for later
+        m_componentRegistry = componentRegistry;
+        m_componentActor = componentActor;
+        m_context = context;
+        m_bundle = context.getBundle();
+
+        // have the LogService handy (if available)
+        m_logService = new ServiceTracker<LogService, LogService>( context, 
Activator.LOGSERVICE_CLASS, null );
+        m_logService.open();
+        m_configuration = configuration;
+
+        log( LogService.LOG_DEBUG, "BundleComponentActivator : Bundle [{0}] 
active",
+                new Object[] {m_bundle.getBundleId()}, null, null, null );
+
+        // Get the Metadata-Location value from the manifest
+        String descriptorLocations = ( String ) m_bundle.getHeaders().get( 
"Service-Component" );
+        if ( descriptorLocations == null )
+        {
+            throw new ComponentException( "Service-Component entry not found 
in the manifest" );
+        }
+
+        initialize( descriptorLocations );
+    }
+
+
+    /**
+     * Gets the MetaData location, parses the meta data and requests the 
processing
+     * of binder instances
+     *
+     * @param descriptorLocations A comma separated list of locations of
+     *      component descriptors. This must not be <code>null</code>.
+     *
+     * @throws IllegalStateException If the bundle has already been 
uninstalled.
+     */
+    private void initialize( String descriptorLocations )
+    {
+        log( LogService.LOG_DEBUG, "BundleComponentActivator : Bundle [{0}] 
descriptor locations {1}",
+                new Object[] {m_bundle.getBundleId(), descriptorLocations}, 
null, null, null );
+
+        // 112.4.1: The value of the the header is a comma separated list of 
XML entries within the Bundle
+        StringTokenizer st = new StringTokenizer( descriptorLocations, ", " );
+
+        while ( st.hasMoreTokens() )
+        {
+            String descriptorLocation = st.nextToken();
+
+            URL[] descriptorURLs = findDescriptors( m_bundle, 
descriptorLocation );
+            if ( descriptorURLs.length == 0 )
+            {
+                // 112.4.1 If an XML document specified by the header cannot 
be located in the bundle and its attached
+                // fragments, SCR must log an error message with the Log 
Service, if present, and continue.
+                log( LogService.LOG_ERROR, "Component descriptor entry ''{0}'' 
not found", new Object[]
+                    { descriptorLocation }, null, null, null );
+                continue;
+            }
+
+            // load from the descriptors
+            for ( URL descriptorURL : descriptorURLs )
+            {
+                loadDescriptor( descriptorURL );
+            }
+        }
+    }
+
+
+    /**
+     * Called outside the constructor so that the m_managers field is 
completely initialized.
+     * A component might possibly start a thread to enable other components, 
which could access m_managers
+     */
+    void initialEnable()
+    {
+        //enable all the enabled components
+        for ( ComponentHolder<?> componentHolder : m_managers )
+        {
+            log( LogService.LOG_DEBUG, "BundleComponentActivator : Bundle 
[{0}] May enable component holder {1}",
+                    new Object[] {m_bundle.getBundleId(), 
componentHolder.getComponentMetadata().getName()}, null, null, null );
+
+            if ( componentHolder.getComponentMetadata().isEnabled() )
+            {
+                log( LogService.LOG_DEBUG, "BundleComponentActivator : Bundle 
[{0}] Enabling component holder {1}",
+                        new Object[] {m_bundle.getBundleId(), 
componentHolder.getComponentMetadata().getName()}, null, null, null );
+
+                try
+                {
+                    componentHolder.enableComponents( false );
+                }
+                catch ( Throwable t )
+                {
+                    // caught on unhandled RuntimeException or Error
+                    // (e.g. ClassDefNotFoundError)
+
+                    // make sure the component is properly disabled, just in 
case
+                    try
+                    {
+                        componentHolder.disableComponents( false );
+                    }
+                    catch ( Throwable ignore )
+                    {
+                    }
+
+                    log( LogService.LOG_ERROR,
+                        "BundleComponentActivator : Bundle [{0}] Unexpected 
failure enabling component holder {1}",
+                        new Object[] { m_bundle.getBundleId(), 
componentHolder.getComponentMetadata().getName() }, null, null, t );
+                }
+            }
+            else
+            {
+                log( LogService.LOG_DEBUG, "BundleComponentActivator : Bundle 
[{0}] Will not enable component holder {1}",
+                        new Object[] {m_bundle.getBundleId(), 
componentHolder.getComponentMetadata().getName()}, null, null, null );
+            }
+        }
+    }
+
+
+    /**
+     * Finds component descriptors based on descriptor location.
+     *
+     * @param bundle bundle to search for descriptor files
+     * @param descriptorLocation descriptor location
+     * @return array of descriptors or empty array if none found
+     */
+    static URL[] findDescriptors( final Bundle bundle, final String 
descriptorLocation )
+    {
+        if ( bundle == null || descriptorLocation == null || 
descriptorLocation.trim().length() == 0 )
+        {
+            return new URL[0];
+        }
+
+        // split pattern and path
+        final int lios = descriptorLocation.lastIndexOf( "/" );
+        final String path;
+        final String filePattern;
+        if ( lios > 0 )
+        {
+            path = descriptorLocation.substring( 0, lios );
+            filePattern = descriptorLocation.substring( lios + 1 );
+        }
+        else
+        {
+            path = "/";
+            filePattern = descriptorLocation;
+        }
+
+        // find the entries
+        final Enumeration<URL> entries = bundle.findEntries( path, 
filePattern, false );
+        if ( entries == null || !entries.hasMoreElements() )
+        {
+            return new URL[0];
+        }
+
+        // create the result list
+        List<URL> urls = new ArrayList<URL>();
+        while ( entries.hasMoreElements() )
+        {
+            urls.add( entries.nextElement() );
+        }
+        return urls.toArray( new URL[urls.size()] );
+    }
+
+
+    private void loadDescriptor( final URL descriptorURL )
+    {
+        // simple path for log messages
+        final String descriptorLocation = descriptorURL.getPath();
+
+        InputStream stream = null;
+        try
+        {
+            stream = descriptorURL.openStream();
+
+            BufferedReader in = new BufferedReader( new InputStreamReader( 
stream, "UTF-8" ) );
+            XmlHandler handler = new XmlHandler( m_bundle, this, 
getConfiguration().isFactoryEnabled(), getConfiguration().keepInstances() );
+            KXml2SAXParser parser;
+
+            parser = new KXml2SAXParser( in );
+
+            parser.parseXML( handler );
+
+            // 112.4.2 Component descriptors may contain a single, root 
component element
+            // or one or more component elements embedded in a larger document
+            for ( Object o : handler.getComponentMetadataList() )
+            {
+                ComponentMetadata metadata = ( ComponentMetadata ) o;
+                ComponentRegistryKey key = null;
+                try
+                {
+                    // check and reserve the component name (if not null)
+                    if ( metadata.getName() != null )
+                    {
+                        key = m_componentRegistry.checkComponentName( 
m_bundle, metadata.getName() );
+                    }
+
+                    // validate the component metadata
+                    metadata.validate( this );
+
+                    // Request creation of the component manager
+                    ComponentHolder<?> holder = 
m_componentRegistry.createComponentHolder( this, metadata );
+
+                    // register the component after validation
+                    m_componentRegistry.registerComponentHolder( key, holder );
+                    m_managers.add( holder );
+
+                    log( LogService.LOG_DEBUG, "BundleComponentActivator : 
Bundle [{0}] ComponentHolder created for {1}",
+                            new Object[] {m_bundle.getBundleId(), 
metadata.getName()}, null, null, null );
+
+                }
+                catch ( Throwable t )
+                {
+                    // There is a problem with this particular component, 
we'll log the error
+                    // and proceed to the next one
+                    log( LogService.LOG_ERROR, "Cannot register Component", 
metadata, null, t );
+
+                    // make sure the name is not reserved any more
+                    if ( key != null )
+                    {
+                        m_componentRegistry.unregisterComponentHolder( key );
+                    }
+                }
+            }
+        }
+        catch ( IOException ex )
+        {
+            // 112.4.1 If an XML document specified by the header cannot be 
located in the bundle and its attached
+            // fragments, SCR must log an error message with the Log Service, 
if present, and continue.
+
+            log( LogService.LOG_ERROR, "Problem reading descriptor entry 
''{0}''", new Object[]
+                { descriptorLocation }, null, null, ex );
+        }
+        catch ( Exception ex )
+        {
+            log( LogService.LOG_ERROR, "General problem with descriptor entry 
''{0}''", new Object[]
+                { descriptorLocation }, null, null, ex );
+        }
+        finally
+        {
+            if ( stream != null )
+            {
+                try
+                {
+                    stream.close();
+                }
+                catch ( IOException ignore )
+                {
+                }
+            }
+        }
+    }
+
+
+    /**
+    * Dispose of this component activator instance and all the component
+    * managers.
+    */
+    void dispose( int reason )
+    {
+        if ( m_active.compareAndSet( true, false ))
+        {
+            log( LogService.LOG_DEBUG, "BundleComponentActivator : Bundle 
[{0}] will destroy {1} instances", new Object[]
+                    { m_bundle.getBundleId(), m_managers.size() }, null, null, 
null );
+
+            for (ComponentHolder<?> holder: m_managers )
+            {
+                try
+                {
+                    holder.disposeComponents( reason );
+                }
+                catch ( Exception e )
+                {
+                    log( LogService.LOG_ERROR, "BundleComponentActivator : 
Exception invalidating", holder
+                            .getComponentMetadata(), null, e );
+                }
+                finally
+                {
+                    m_componentRegistry.unregisterComponentHolder( m_bundle, 
holder.getComponentMetadata()
+                            .getName() );
+                }
+
+            }
+
+            log( LogService.LOG_DEBUG, "BundleComponentActivator : Bundle 
[{0}] STOPPED", new Object[]
+                    {m_bundle.getBundleId()}, null, null, null );
+
+            m_logService.close();
+            m_closeLatch.countDown();
+        }
+        else
+        {
+            try
+            {
+                m_closeLatch.await(m_configuration.lockTimeout(), 
TimeUnit.MILLISECONDS);
+            }
+            catch ( InterruptedException e )
+            {
+                //ignore interruption during concurrent shutdown.
+            }
+        }
+
+    }
+
+
+    /**
+     * Returns <true> if this instance is active, that is if components
+     * may be activated for this component. The active flag is set early
+     * in the constructor indicating the activator is basically active
+     * (not fully setup, though) and reset early in the process of
+     * {@link #dispose(int) disposing} this instance.
+     */
+    public boolean isActive()
+    {
+        return m_active.get();
+    }
+
+
+    /**
+    * Returns the BundleContext
+    *
+    * @return the BundleContext
+    */
+    public BundleContext getBundleContext()
+    {
+        return m_context;
+    }
+
+
+    public ScrConfiguration getConfiguration()
+    {
+        return m_configuration;
+    }
+
+
+    /**
+     * Implements the <code>ComponentContext.enableComponent(String)</code>
+     * method by first finding the component(s) for the <code>name</code> and
+     * enabling them.  The enable method will schedule activation.
+     * <p>
+     *
+     * @param name The name of the component to enable or <code>null</code> to
+     *      enable all components.
+     */
+    public void enableComponent( final String name )
+    {
+        final List<ComponentHolder<?>> holder = getSelectedComponents( name );
+        for ( ComponentHolder<?> aHolder : holder )
+        {
+            try
+            {
+                log( LogService.LOG_DEBUG, "Enabling Component", 
aHolder.getComponentMetadata(), null, null );
+                aHolder.enableComponents( true );
+            }
+            catch ( Throwable t )
+            {
+                log( LogService.LOG_ERROR, "Cannot enable component", 
aHolder.getComponentMetadata(), null, t );
+            }
+        }
+    }
+
+
+    /**
+     * Implements the <code>ComponentContext.disableComponent(String)</code>
+     * method by first finding the component(s) for the <code>name</code> and
+     * disabling them.  The disable method will schedule deactivation
+     * <p>
+     *
+     * @param name The name of the component to disable or <code>null</code> to
+     *      disable all components.
+     */
+    public void disableComponent( final String name )
+    {
+        final List<ComponentHolder<?>> holder = getSelectedComponents( name );
+        for ( ComponentHolder<?> aHolder : holder )
+        {
+            try
+            {
+                log( LogService.LOG_DEBUG, "Disabling Component", 
aHolder.getComponentMetadata(), null, null );
+                aHolder.disableComponents( true );
+            }
+            catch ( Throwable t )
+            {
+                log( LogService.LOG_ERROR, "Cannot disable component", 
aHolder.getComponentMetadata(), null, t );
+            }
+        }
+    }
+
+
+    /**
+     * Returns an array of {@link ComponentHolder} instances which match the
+     * <code>name</code>. If the <code>name</code> is <code>null</code> an
+     * array of all currently known component managers is returned. Otherwise
+     * an array containing a single component manager matching the name is
+     * returned if one is registered. Finally, if no component manager with the
+     * given name is registered, <code>null</code> is returned.
+     *
+     * @param name The name of the component manager to return or
+     *      <code>null</code> to return an array of all component managers.
+     *
+     * @return An array containing one or more component managers according
+     *      to the <code>name</code> parameter or <code>null</code> if no
+     *      component manager with the given name is currently registered.
+     */
+    private List<ComponentHolder<?>> getSelectedComponents( String name )
+    {
+        // if all components are selected
+        if ( name == null )
+        {
+            return m_managers;
+        }
+
+        ComponentHolder<?> componentHolder = 
m_componentRegistry.getComponentHolder( m_bundle, name );
+        if (componentHolder != null)
+        {
+            return Collections.<ComponentHolder<?>>singletonList( 
componentHolder );
+        }
+
+        // if the component is not known
+        return Collections.emptyList();
+    }
+
+
+    //---------- Component ID support
+
+    public long registerComponentId(AbstractComponentManager<?> 
componentManager) {
+        return m_componentRegistry.registerComponentId(componentManager);
+    }
+
+    public void unregisterComponentId(AbstractComponentManager<?> 
componentManager) {
+        m_componentRegistry.unregisterComponentId(componentManager.getId());
+    }
+
+    //---------- Asynchronous Component Handling ------------------------------
+
+    /**
+     * Schedules the given <code>task</code> for asynchrounous execution or
+     * synchronously runs the task if the thread is not running. If this 
instance
+     * is {@link #isActive() not active}, the task is not executed.
+     *
+     * @param task The component task to execute
+     */
+    public void schedule( Runnable task )
+    {
+        if ( isActive() )
+        {
+            ComponentActorThread cat = m_componentActor;
+            if ( cat != null )
+            {
+                cat.schedule( task );
+            }
+            else
+            {
+                log( LogService.LOG_DEBUG, "Component Actor Thread not 
running, calling synchronously", null, null, null );
+                try
+                {
+                    synchronized ( this )
+                    {
+                        task.run();
+                    }
+                }
+                catch ( Throwable t )
+                {
+                    log( LogService.LOG_WARNING, "Unexpected problem executing 
task", null, null, t );
+                }
+            }
+        }
+        else
+        {
+            log( LogService.LOG_WARNING, "BundleComponentActivator is not 
active; not scheduling {0}", new Object[]
+                { task }, null, null, null );
+        }
+    }
+
+
+    /**
+     * Returns <code>true</code> if logging for the given level is enabled.
+     */
+    public boolean isLogEnabled( int level )
+    {
+        return m_configuration.getLogLevel() >= level;
+    }
+
+
+    /**
+     * Method to actually emit the log message. If the LogService is available,
+     * the message will be logged through the LogService. Otherwise the message
+     * is logged to stdout (or stderr in case of LOG_ERROR level messages),
+     *
+     * @param level The log level to log the message at
+     * @param pattern The <code>java.text.MessageFormat</code> message format
+     *      string for preparing the message
+     * @param arguments The format arguments for the <code>pattern</code>
+ *      string.
+     * @param componentId
+     * @param ex An optional <code>Throwable</code> whose stack trace is 
written,
+     */
+    public void log( int level, String pattern, Object[] arguments, 
ComponentMetadata metadata, Long componentId, Throwable ex )
+    {
+        if ( isLogEnabled( level ) )
+        {
+            final String message = MessageFormat.format( pattern, arguments );
+            log( level, message, metadata, componentId, ex );
+        }
+    }
+
+
+    /**
+     * Method to actually emit the log message. If the LogService is available,
+     * the message will be logged through the LogService. Otherwise the message
+     * is logged to stdout (or stderr in case of LOG_ERROR level messages),
+     *
+     * @param level The log level to log the message at
+     * @param message The message to log
+     * @param componentId
+     * @param ex An optional <code>Throwable</code> whose stack trace is 
written,
+     */
+    public void log( int level, String message, ComponentMetadata metadata, 
Long componentId, Throwable ex )
+    {
+        if ( isLogEnabled( level ) )
+        {
+            // prepend the metadata name to the message
+            if ( metadata != null )
+            {
+                if ( componentId != null )
+                {
+                    message = "[" + metadata.getName() + "(" + componentId + 
")] " + message;
+                }
+                else
+                {
+                    message = "[" + metadata.getName() + "] " + message;
+                }
+            }
+
+            ServiceTracker<LogService, LogService> logService = m_logService;
+            if ( logService != null )
+            {
+                LogService logger = logService.getService();
+                if ( logger == null )
+                {
+                    Activator.log( level, m_bundle, message, ex );
+                }
+                else
+                {
+                    logger.log( level, message, ex );
+                }
+            }
+            else
+            {
+                // BCA has been disposed off, bundle context is probably 
invalid. Try to log something.
+                Activator.log( level, null, message, ex );
+            }
+        }
+    }
+
+    public void missingServicePresent( ServiceReference<?> serviceReference )
+    {
+        m_componentRegistry.missingServicePresent( serviceReference, 
m_componentActor );
+    }
+
+    public <T> void registerMissingDependency( DependencyManager<?, T> 
dependencyManager, ServiceReference<T> serviceReference, int trackingCount )
+    {
+        m_componentRegistry.registerMissingDependency(dependencyManager, 
serviceReference, trackingCount );
+    }
+}

Added: 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ComponentActorThread.java
URL: 
http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ComponentActorThread.java?rev=1689973&view=auto
==============================================================================
--- 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ComponentActorThread.java
 (added)
+++ 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ComponentActorThread.java
 Wed Jul  8 22:10:14 2015
@@ -0,0 +1,154 @@
+/*
+ * 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.util.LinkedList;
+
+import org.osgi.service.log.LogService;
+
+
+/**
+ * The <code>ComponentActorThread</code> is the thread used to act upon 
registered
+ * components of the service component runtime.
+ */
+class ComponentActorThread implements Runnable
+{
+
+    // sentinel task to terminate this thread
+    private static final Runnable TERMINATION_TASK = new Runnable()
+    {
+        public void run()
+        {
+        }
+
+
+        public String toString()
+        {
+            return "Component Actor Terminator";
+        }
+    };
+
+    // the queue of Runnable instances  to be run
+    private LinkedList<Runnable> tasks;
+
+
+    ComponentActorThread()
+    {
+        tasks = new LinkedList<Runnable>();
+    }
+
+
+    // waits on Runnable instances coming into the queue. As instances come
+    // in, this method calls the Runnable.run method, logs any exception
+    // happening and keeps on waiting for the next Runnable. If the Runnable
+    // taken from the queue is this thread instance itself, the thread
+    // terminates.
+    public void run()
+    {
+        Activator.log( LogService.LOG_DEBUG, null, "Starting 
ComponentActorThread", null );
+
+        for ( ;; )
+        {
+            final Runnable task;
+            synchronized ( tasks )
+            {
+                while ( tasks.isEmpty() )
+                {
+                    try
+                    {
+                        tasks.wait();
+                    }
+                    catch ( InterruptedException ie )
+                    {
+                        Thread.currentThread().interrupt();
+                        // don't care
+                    }
+                }
+
+                task = tasks.removeFirst();
+            }
+
+            try
+            {
+                // return if the task is this thread itself
+                if ( task == TERMINATION_TASK )
+                {
+                    Activator.log( LogService.LOG_DEBUG, null, "Shutting down 
ComponentActorThread", null );
+                    return;
+                }
+
+                // otherwise execute the task, log any issues
+                Activator.log( LogService.LOG_DEBUG, null, "Running task: " + 
task, null );
+                task.run();
+            }
+            catch ( Throwable t )
+            {
+                Activator.log( LogService.LOG_ERROR, null, "Unexpected problem 
executing task " + task, t );
+            }
+            finally
+            {
+                synchronized ( tasks )
+                {
+                    tasks.notifyAll();
+                }
+            }
+        }
+    }
+
+
+    // cause this thread to terminate by adding this thread to the end
+    // of the queue
+    void terminate()
+    {
+        schedule( TERMINATION_TASK );
+        synchronized ( tasks )
+        {
+            while ( !tasks.isEmpty() )
+            {
+                try
+                {
+                    tasks.wait();
+                }
+                catch ( InterruptedException e )
+                {
+                    Thread.currentThread().interrupt();
+                    Activator.log( LogService.LOG_ERROR, null, "Interrupted 
exception waiting for queue to empty", e );
+                }
+            }
+        }
+    }
+
+
+    // queue the given runnable to be run as soon as possible
+    void schedule( Runnable task )
+    {
+        synchronized ( tasks )
+        {
+            // append to the task queue
+            tasks.add( task );
+
+            Activator.log( LogService.LOG_DEBUG, null, "Adding task [{0}] as 
#{1} in the queue" 
+                    , new Object[] {task, tasks.size()}, null );
+
+            // notify the waiting thread
+            tasks.notifyAll();
+        }
+    }
+}

Added: 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ComponentRegistry.java
URL: 
http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ComponentRegistry.java?rev=1689973&view=auto
==============================================================================
--- 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ComponentRegistry.java
 (added)
+++ 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ComponentRegistry.java
 Wed Jul  8 22:10:14 2015
@@ -0,0 +1,621 @@
+/*
+ * 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.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.scr.impl.config.ComponentHolder;
+import org.apache.felix.scr.impl.config.ConfigurableComponentHolder;
+import org.apache.felix.scr.impl.config.ConfigurationSupport;
+import org.apache.felix.scr.impl.manager.AbstractComponentManager;
+import org.apache.felix.scr.impl.manager.DependencyManager;
+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.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.component.ComponentException;
+import org.osgi.service.log.LogService;
+
+
+/**
+ * The <code>ComponentRegistry</code> class acts as the global registry for
+ * components by name and by component ID.
+ */
+public class ComponentRegistry implements 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 null (for name reservations) or implementations
+     * of the {@link ComponentHolder} interface.
+     * <p>
+     * The {@link #checkComponentName(String)} will first add an entry to this
+     * map with null value to reserve the name. After setting up
+     * the component, the {@link #registerComponentHolder(String, 
ComponentHolder)}
+     * method replaces the value of the named entry with the actual
+     * {@link ComponentHolder}.
+     *
+     * @see #checkComponentName(String)
+     * @see #registerComponentHolder(String, ComponentHolder)
+     * @see #unregisterComponentHolder(String)
+     */
+    private final Map<ComponentRegistryKey, ComponentHolder<?>> 
m_componentHoldersByName;
+
+    /**
+     * The map of known components indexed by component configuration pid. The 
values are
+     * Sets of the {@link ComponentHolder} interface. Normally, the 
configuration pid
+     * is the component name, but since DS 1.2 (OSGi 4.3), a component may 
specify a specific
+     * pid, and it is possible that different components refer to the same 
pid. That's why
+     * the values of this map are Sets of ComponentHolders, allowing to lookup 
all components
+     * which are using a given configuration pid.
+     * This map is used when the ConfigurationSupport detects that a CM pid is 
updated. When
+     * a PID is updated, the ConfigurationSupport listener class invokes the
+     * {@link #getComponentHoldersByPid(String)} method which returns an 
iterator over all
+     * components that are using the given pid for configuration.
+     * <p>
+     *
+     * @see #registerComponentHolder(String, ComponentHolder)
+     * @see #unregisterComponentHolder(String)
+     * @see 
ConfigurationSupport#configurationEvent(org.osgi.service.cm.ConfigurationEvent)
+     */
+    private final Map<String, Set<ComponentHolder<?>>> m_componentHoldersByPid;
+
+    /**
+     * Map of components by component ID. This map indexed by the component
+     * ID number (<code>java.lang.Long</code>) contains the actual
+     * {@link AbstractComponentManager} instances existing in the system.
+     *
+     * @see #registerComponentId(AbstractComponentManager)
+     * @see #unregisterComponentId(long)
+     */
+    private final Map<Long, AbstractComponentManager<?>> m_componentsById;
+
+    /**
+     * Counter to setup the component IDs as issued by the
+     * {@link #registerComponentId(AbstractComponentManager)} method. This
+     * counter is only incremented.
+     */
+    private long m_componentCounter = -1;
+
+    // ConfigurationAdmin support -- created on demand upon availability of
+    // the ConfigurationAdmin service
+    private ConfigurationSupport configurationSupport;
+
+    private final Map<ServiceReference<?>, List<Entry<?, ?>>> 
m_missingDependencies = new HashMap<ServiceReference<?>, List<Entry<?, ?>>>( );
+
+    protected ComponentRegistry( final BundleContext context )
+    {
+        m_bundleContext = context;
+        m_componentHoldersByName = new HashMap<ComponentRegistryKey, 
ComponentHolder<?>>();
+        m_componentHoldersByPid = new HashMap<String, 
Set<ComponentHolder<?>>>();
+        m_componentsById = new HashMap<Long, AbstractComponentManager<?>>();
+
+        // keep me informed on ConfigurationAdmin state changes
+        try
+        {
+            context.addServiceListener(this, "(objectclass=" + 
CONFIGURATION_ADMIN + ")");
+        }
+        catch (InvalidSyntaxException ise)
+        {
+            // not expected (filter is tested valid)
+        }
+
+        // If the Configuration Admin Service is already registered, setup
+        // configuration support immediately
+        if (context.getServiceReference(CONFIGURATION_ADMIN) != null)
+        {
+            getOrCreateConfigurationSupport();
+        }
+    }
+
+    public void dispose()
+    {
+        m_bundleContext.removeServiceListener(this);
+
+        if (configurationSupport != null)
+        {
+            configurationSupport.dispose();
+            configurationSupport = null;
+        }
+    }
+
+
+
+    //---------- ComponentManager registration by component Id
+
+    /**
+     * Assigns a unique ID to the component, internally registers the
+     * component under that ID and returns the assigned component ID.
+     *
+     * @param componentManager The {@link AbstractComponentManager} for which
+     *      to assign a component ID and which is to be internally registered
+     *
+     * @return the assigned component ID
+     */
+    final long registerComponentId( final AbstractComponentManager<?> 
componentManager )
+    {
+        long componentId;
+        synchronized ( m_componentsById )
+        {
+            componentId = ++m_componentCounter;
+
+            m_componentsById.put( componentId, componentManager );
+        }
+
+        return componentId;
+    }
+
+
+    /**
+     * Unregisters the component with the given component ID from the internal
+     * registry. After unregistration, the component ID should be considered
+     * invalid.
+     *
+     * @param componentId The ID of the component to be removed from the
+     *      internal component registry.
+     */
+    final void unregisterComponentId( final long componentId )
+    {
+        synchronized ( m_componentsById )
+        {
+            m_componentsById.remove( componentId );
+        }
+    }
+
+
+    //---------- ComponentHolder registration by component name
+
+    /**
+     * Checks whether the component name is "globally" unique or not. If it is
+     * unique, it is reserved until the actual component is registered with
+     * {@link #registerComponentHolder(String, ComponentHolder)} or until
+     * it is unreserved by calling {@link #unregisterComponentHolder(String)}.
+     * If a component with the same name has already been reserved or 
registered
+     * a ComponentException is thrown with a descriptive message.
+     *
+     * @param bundle the bundle registering the component
+     * @param name the component name to check and reserve
+     * @throws ComponentException if the name is already in use by another
+     *      component.
+     */
+    final ComponentRegistryKey checkComponentName( final Bundle bundle, final 
String name )
+    {
+        // register the name if no registration for that name exists already
+        final ComponentRegistryKey key = new ComponentRegistryKey( bundle, 
name );
+        ComponentHolder<?> existingRegistration = null;
+        boolean present;
+        synchronized ( m_componentHoldersByName )
+        {
+            present = m_componentHoldersByName.containsKey( key );
+            if ( !present )
+            {
+                m_componentHoldersByName.put( key, null );
+            }
+            else
+            {
+                existingRegistration = m_componentHoldersByName.get( key );
+            }
+        }
+
+        // there was a registration already, throw an exception and use the
+        // existing registration to provide more information if possible
+        if ( present )
+        {
+            String message = "The component name '" + name + "' has already 
been registered";
+
+            if ( existingRegistration != null )
+            {
+                Bundle cBundle = 
existingRegistration.getActivator().getBundleContext().getBundle();
+                ComponentMetadata cMeta = 
existingRegistration.getComponentMetadata();
+
+                StringBuffer buf = new StringBuffer( message );
+                buf.append( " by Bundle " ).append( cBundle.getBundleId() );
+                if ( cBundle.getSymbolicName() != null )
+                {
+                    buf.append( " (" ).append( cBundle.getSymbolicName() 
).append( ")" );
+                }
+                buf.append( " as Component of Class " ).append( 
cMeta.getImplementationClassName() );
+                message = buf.toString();
+            }
+
+            throw new ComponentException( message );
+        }
+
+        return key;
+    }
+
+
+    /**
+     * Registers the given component under the given name. If the name has not
+     * already been reserved calling {@link #checkComponentName(String)} this
+     * method throws a {@link ComponentException}.
+     *
+     * @param name The name to register the component under
+     * @param componentHolder The component to register
+     *
+     * @throws ComponentException if the name has not been reserved through
+     *      {@link #checkComponentName(String)} yet.
+     */
+    final void registerComponentHolder( final ComponentRegistryKey key, 
ComponentHolder<?> componentHolder )
+    {
+        Activator.log(LogService.LOG_DEBUG, null,
+                "Registering component with pid {0} for bundle {1}",
+                new Object[] 
{componentHolder.getComponentMetadata().getConfigurationPid(), 
key.getBundleId()},
+                null);
+        synchronized ( m_componentHoldersByName )
+        {
+            // only register the component if there is a m_registration for it 
!
+            if ( m_componentHoldersByName.get( key ) != null )
+            {
+                // this is not expected if all works ok
+                throw new ComponentException( "The component name '{0}" + 
componentHolder.getComponentMetadata().getName()
+                    + "' has already been registered." );
+            }
+
+            m_componentHoldersByName.put( key, componentHolder );
+        }
+
+        synchronized (m_componentHoldersByPid)
+        {
+            // See if the component declares a specific configuration pid 
(112.4.4 configuration-pid)
+            List<String> configurationPids = 
componentHolder.getComponentMetadata().getConfigurationPid();
+
+            for ( String configurationPid: configurationPids )
+            {
+                // Since several components may refer to the same 
configuration pid, we have to
+                // store the component holder in a Set, in order to be able to 
lookup every
+                // components from a given pid.
+                Set<ComponentHolder<?>> set = m_componentHoldersByPid.get( 
configurationPid );
+                if ( set == null )
+                {
+                    set = new HashSet<ComponentHolder<?>>();
+                    m_componentHoldersByPid.put( configurationPid, set );
+                }
+                set.add( componentHolder );
+            }
+        }
+
+        if (configurationSupport != null)
+        {
+            configurationSupport.configureComponentHolder(componentHolder);
+        }
+
+  }
+
+    /**
+     * Returns the component registered under the given name or 
<code>null</code>
+     * if no component is registered yet.
+     */
+    public final ComponentHolder<?> getComponentHolder( final Bundle bundle, 
final String name )
+    {
+        synchronized ( m_componentHoldersByName )
+        {
+            return m_componentHoldersByName.get( new ComponentRegistryKey( 
bundle, name ) );
+        }
+    }
+
+    /**
+     * Returns the set of ComponentHolder instances whose configuration pids 
are matching
+     * the given pid.
+     * @param pid the pid candidate
+     * @return the set of ComponentHolders matching the singleton pid supplied
+     */
+    public final Collection<ComponentHolder<?>> 
getComponentHoldersByPid(TargetedPID targetedPid)
+    {
+        String pid = targetedPid.getServicePid();
+        Set<ComponentHolder<?>> componentHoldersUsingPid = new 
HashSet<ComponentHolder<?>>();
+        synchronized (m_componentHoldersByPid)
+        {
+            Set<ComponentHolder<?>> set = m_componentHoldersByPid.get(pid);
+            // only return the entry if non-null and not a reservation
+            if (set != null)
+            {
+                for (ComponentHolder<?> holder: set)
+                {
+                    if (targetedPid.matchesTarget(holder))
+                    {
+                        componentHoldersUsingPid.add( holder );
+                    }
+                }
+            }
+        }
+        return componentHoldersUsingPid;
+    }
+
+    /**
+     * Returns an array of all values currently stored in the component holders
+     * map. The entries in the array are either String types for component
+     * name reservations or {@link ComponentHolder} instances for actual
+     * holders of components.
+     */
+    public final List<ComponentHolder<?>> getComponentHolders()
+    {
+       List<ComponentHolder<?>> all = new ArrayList<ComponentHolder<?>>();
+        synchronized ( m_componentHoldersByName )
+        {
+               all.addAll(m_componentHoldersByName.values());
+        }
+        return all;
+    }
+
+    public final List<ComponentHolder<?>> getComponentHolders(Bundle...bundles)
+    {
+       List<ComponentHolder<?>> all =getComponentHolders();
+        List<ComponentHolder<?>> holders = new ArrayList<ComponentHolder<?>>();
+        for ( ComponentHolder<?> holder: all)
+        {
+               BundleComponentActivator activator = holder.getActivator();
+               if (activator != null)
+               {
+                       Bundle holderBundle = 
activator.getBundleContext().getBundle();
+                       for (Bundle b: bundles)
+                       {
+                               if (b == holderBundle)
+                               {
+                                       holders.add(holder);
+                               }
+                       }
+               }
+        }
+        return holders;
+    }
+
+
+    /**
+     * Removes the component registered under that name. If no component is
+     * yet registered but the name is reserved, it is unreserved.
+     * <p>
+     * After calling this method, the name can be reused by other components.
+     */
+    final void unregisterComponentHolder( final Bundle bundle, final String 
name )
+    {
+        unregisterComponentHolder( new ComponentRegistryKey( bundle, name ) );
+    }
+
+
+    /**
+     * Removes the component registered under that name. If no component is
+     * yet registered but the name is reserved, it is unreserved.
+     * <p>
+     * After calling this method, the name can be reused by other components.
+     */
+    final void unregisterComponentHolder( final ComponentRegistryKey key )
+    {
+        ComponentHolder<?> component;
+        synchronized ( m_componentHoldersByName )
+        {
+            component = m_componentHoldersByName.remove( key );
+        }
+
+        if (component != null) {
+            Activator.log(LogService.LOG_DEBUG, null,
+                    "Unregistering component with pid {0} for bundle {1}",
+                    new Object[] 
{component.getComponentMetadata().getConfigurationPid(), key.getBundleId()}, 
null);
+            synchronized (m_componentHoldersByPid)
+            {
+                List<String> configurationPids = 
component.getComponentMetadata().getConfigurationPid();
+                for ( String configurationPid: configurationPids )
+                {
+                    Set<ComponentHolder<?>> componentsForPid = 
m_componentHoldersByPid.get( configurationPid );
+                    if ( componentsForPid != null )
+                    {
+                        componentsForPid.remove( component );
+                        if ( componentsForPid.size() == 0 )
+                        {
+                            m_componentHoldersByPid.remove( configurationPid );
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    //---------- base configuration support
+
+    /**
+     * Factory method to issue {@link ComponentHolder} instances to manage
+     * components described by the given component <code>metadata</code>.
+     */
+    public <S> ComponentHolder<S> createComponentHolder( 
BundleComponentActivator activator, ComponentMetadata metadata )
+    {
+        return new ConfigurableComponentHolder<S>(activator, metadata);
+    }
+
+
+    //---------- 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)
+        {
+            ConfigurationSupport configurationSupport = 
getOrCreateConfigurationSupport();
+
+            final ServiceReference<ConfigurationAdmin> caRef = 
(ServiceReference<ConfigurationAdmin>) event.getServiceReference();
+            final ConfigurationAdmin service = 
m_bundleContext.getService(caRef);
+            if (service != null)
+            {
+                try
+                {
+                    configurationSupport.configureComponentHolders(caRef, 
service);
+                }
+                finally
+                {
+                    m_bundleContext.ungetService(caRef);
+                }
+            }
+        }
+        else if (event.getType() == ServiceEvent.UNREGISTERING)
+        {
+            disposeConfigurationSupport();
+        }
+    }
+
+    //---------- Helper method
+
+    /**
+     * Returns <code>true</code> if the <code>bundle</code> is to be considered
+     * active from the perspective of declarative services.
+     * <p>
+     * As of R4.1 a bundle may have lazy activation policy which means a bundle
+     * remains in the STARTING state until a class is loaded from that bundle
+     * (unless that class is declared to not cause the bundle to start). And
+     * thus for DS 1.1 this means components are to be loaded for lazily 
started
+     * bundles being in the STARTING state (after the LAZY_ACTIVATION event) 
has
+     * been sent.  Hence DS must consider a bundle active when it is really
+     * active and when it is a lazily activated bundle in the STARTING state.
+     *
+     * @param bundle The bundle check
+     * @return <code>true</code> if <code>bundle</code> is not 
<code>null</code>
+     *          and the bundle is either active or has lazy activation policy
+     *          and is in the starting state.
+     *
+     * @see <a 
href="https://issues.apache.org/jira/browse/FELIX-1666";>FELIX-1666</a>
+     */
+    static boolean isBundleActive( final Bundle bundle )
+    {
+        if ( bundle != null )
+        {
+            if ( bundle.getState() == Bundle.ACTIVE )
+            {
+                return true;
+            }
+
+            if ( bundle.getState() == Bundle.STARTING )
+            {
+                // according to the spec the activationPolicy header is only
+                // set to request a bundle to be lazily activated. So in this
+                // simple check we just verify the header is set to assume
+                // the bundle is considered a lazily activated bundle
+                return bundle.getHeaders().get( 
Constants.BUNDLE_ACTIVATIONPOLICY ) != null;
+            }
+        }
+
+        // fall back: bundle is not considered active
+        return false;
+    }
+
+    private ConfigurationSupport getOrCreateConfigurationSupport()
+    {
+        if (configurationSupport == null)
+        {
+            configurationSupport = new ConfigurationSupport(m_bundleContext, 
this);
+        }
+        return configurationSupport;
+    }
+
+    private void disposeConfigurationSupport()
+    {
+        if (configurationSupport != null)
+        {
+            this.configurationSupport.dispose();
+            this.configurationSupport = null;
+        }
+    }
+
+    public synchronized <T> void missingServicePresent( final 
ServiceReference<T> serviceReference, ComponentActorThread actor )
+    {
+        final List<Entry<?, ?>> dependencyManagers = 
m_missingDependencies.remove( serviceReference );
+        if ( dependencyManagers != null )
+        {
+            actor.schedule( new Runnable()
+            {
+
+                public void run()
+                {
+                    for ( Entry<?, ?> entry : dependencyManagers )
+                    {
+                        ((DependencyManager<?, 
T>)entry.getDm()).invokeBindMethodLate( serviceReference, 
entry.getTrackingCount() );
+                    }
+                }
+
+                @Override
+                public String toString()
+                {
+                    return "Late binding task of reference " + 
serviceReference + " for dependencyManagers " + dependencyManagers;
+                }
+
+            } );
+        }
+    }
+
+    public synchronized <S, T> void registerMissingDependency( 
DependencyManager<S, T> dependencyManager, ServiceReference<T> 
serviceReference, int trackingCount )
+    {
+        //check that the service reference is from scr
+        if ( serviceReference.getProperty( ComponentConstants.COMPONENT_NAME ) 
== null || serviceReference.getProperty( ComponentConstants.COMPONENT_ID ) == 
null )
+        {
+            return;
+        }
+        List<Entry<?, ?>> dependencyManagers = m_missingDependencies.get( 
serviceReference );
+        if ( dependencyManagers == null )
+        {
+            dependencyManagers = new ArrayList<Entry<?, ?>>();
+            m_missingDependencies.put( serviceReference, dependencyManagers );
+        }
+        dependencyManagers.add( new Entry<S, T>( dependencyManager, 
trackingCount ) );
+    }
+
+    private static class Entry<S,T>
+    {
+        private final DependencyManager<S, T> dm;
+        private final int trackingCount;
+
+        private Entry( DependencyManager<S, T> dm, int trackingCount )
+        {
+            this.dm = dm;
+            this.trackingCount = trackingCount;
+        }
+
+        public DependencyManager<S, T> getDm()
+        {
+            return dm;
+        }
+
+        public int getTrackingCount()
+        {
+            return trackingCount;
+        }
+    }
+}

Added: 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ComponentRegistryKey.java
URL: 
http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ComponentRegistryKey.java?rev=1689973&view=auto
==============================================================================
--- 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ComponentRegistryKey.java
 (added)
+++ 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ComponentRegistryKey.java
 Wed Jul  8 22:10:14 2015
@@ -0,0 +1,83 @@
+/*
+ * 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.osgi.framework.Bundle;
+
+
+/**
+ * The <code>ComponentRegistryKey</code> isused as the key in the
+ * component register to register components by their names.
+ * <p>
+ * Two instances of this class are equal if they are the same or if there
+ * component name and bundle ID is equal.
+ */
+final class ComponentRegistryKey
+{
+
+    private final long bundleId;
+    private final String componentName;
+
+
+    ComponentRegistryKey( final Bundle bundle, final String componentName )
+    {
+        this.bundleId = bundle.getBundleId();
+        this.componentName = componentName;
+    }
+
+
+    public int hashCode()
+    {
+        int code = ( int ) this.bundleId;
+        code += 31 * this.componentName.hashCode();
+        return code;
+    }
+
+
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+
+        if ( obj instanceof ComponentRegistryKey )
+        {
+            ComponentRegistryKey other = ( ComponentRegistryKey ) obj;
+            return this.bundleId == other.bundleId && 
this.componentName.equals( other.componentName );
+        }
+
+        return false;
+    }
+
+
+    public long getBundleId()
+    {
+        return bundleId;
+    }
+
+
+    public String getComponentName()
+    {
+        return componentName;
+    }
+    
+    
+}

Added: 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrCommand.java
URL: 
http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrCommand.java?rev=1689973&view=auto
==============================================================================
--- 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrCommand.java
 (added)
+++ 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrCommand.java
 Wed Jul  8 22:10:14 2015
@@ -0,0 +1,575 @@
+/*
+ * 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.PrintWriter;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+
+import org.apache.felix.scr.info.ScrInfo;
+import org.apache.felix.scr.impl.config.ScrConfiguration;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.dto.ServiceReferenceDTO;
+import org.osgi.service.component.runtime.ServiceComponentRuntime;
+import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
+import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;
+import org.osgi.service.component.runtime.dto.ReferenceDTO;
+import org.osgi.service.component.runtime.dto.SatisfiedReferenceDTO;
+import org.osgi.service.component.runtime.dto.UnsatisfiedReferenceDTO;
+
+/**
+ * The <code>ScrCommand</code> class provides the implementations for the
+ * Apache Felix Gogo and legacy Apache Felix Shell commands. The
+ * {@link #register(BundleContext, ScrService, ScrConfiguration)} method
+ * instantiates and registers the Gogo and Shell commands as possible.
+ */
+public class ScrCommand implements ScrInfo
+{
+
+    private final BundleContext bundleContext;
+    private final ServiceComponentRuntime scrService;
+    private final ScrConfiguration scrConfiguration;
+    
+    private ServiceRegistration<ScrInfo> reg;
+    private ServiceRegistration<?> gogoReg;
+    private ServiceRegistration<?> shellReg;
+
+    static ScrCommand register(BundleContext bundleContext, 
ServiceComponentRuntime scrService, ScrConfiguration scrConfiguration)
+    {
+        final ScrCommand cmd = new ScrCommand(bundleContext, scrService, 
scrConfiguration);
+
+        cmd.registerCommands(bundleContext, scrService);
+        return cmd;
+    }
+
+    //used by ComponentTestBase
+    protected ScrCommand(BundleContext bundleContext, ServiceComponentRuntime 
scrService, ScrConfiguration scrConfiguration)
+    {
+        this.bundleContext = bundleContext;
+        this.scrService = scrService;
+        this.scrConfiguration = scrConfiguration;
+    }
+
+    private void registerCommands(BundleContext bundleContext,
+        ServiceComponentRuntime scrService)
+    {
+        /*
+         * Register the Gogo Command as a service of its own class.
+         * Due to a race condition during project building (this class is
+         * compiled for Java 1.3 compatibility before the required
+         * ScrGogoCommand class compiled for Java 5 compatibility) this uses
+         * reflection to load and instantiate the class. Any failure during 
this
+         * process is just ignored.
+         */
+        try
+        {
+            final String scrGogoCommandClassName = 
"org.apache.felix.scr.impl.ScrGogoCommand";
+            final Class<?> scrGogoCommandClass = 
scrService.getClass().getClassLoader().loadClass(scrGogoCommandClassName);
+            final Constructor c = scrGogoCommandClass.getConstructor(new 
Class[]
+                { ScrCommand.class });
+            final Object gogoCmd = c.newInstance(new Object[]
+                { this });
+            final Hashtable<String, Object> props = new Hashtable<String, 
Object>();
+            props.put("osgi.command.scope", "scr");
+            props.put("osgi.command.function", new String[]
+                { "config", "disable", "enable", "info", "list" });
+            props.put(Constants.SERVICE_DESCRIPTION, "SCR Gogo Shell Support");
+            props.put(Constants.SERVICE_VENDOR, "The Apache Software 
Foundation");
+            gogoReg = bundleContext.registerService(scrGogoCommandClassName, 
gogoCmd, props);
+        }
+        catch (Throwable t)
+        {
+            // Might be thrown if running in a pre-Java 5 VM
+        }
+
+        // We dynamically import the impl service API, so it
+        // might not actually be available, so be ready to catch
+        // the exception when we try to register the command service.
+        try
+        {
+            // Register "scr" impl command service as a
+            // wrapper for the bundle repository service.
+            final Hashtable<String, Object> props = new Hashtable<String, 
Object>();
+            props.put(Constants.SERVICE_DESCRIPTION, "SCR Legacy Shell 
Support");
+            props.put(Constants.SERVICE_VENDOR, "The Apache Software 
Foundation");
+            shellReg = 
bundleContext.registerService(org.apache.felix.shell.Command.class, new 
ScrShellCommand(this),
+                props);
+        }
+        catch (Throwable th)
+        {
+            // Ignore.
+        }
+    }
+
+    void unregister()
+    {
+        if (gogoReg != null)
+        {
+            gogoReg.unregister();
+            gogoReg = null;
+        }
+        if ( shellReg != null )
+        {
+            shellReg.unregister();
+            shellReg = null;
+        }
+    }
+
+    // ---------- Actual implementation
+
+    
+    public void update( boolean infoAsService )
+    {
+        if (infoAsService)
+        {
+            if ( reg == null )
+            {
+                final Hashtable<String, Object> props = new Hashtable<String, 
Object>();
+                props.put(Constants.SERVICE_DESCRIPTION, "SCR Info service");
+                props.put(Constants.SERVICE_VENDOR, "The Apache Software 
Foundation");
+                reg = bundleContext.registerService( ScrInfo.class, this, 
props );
+            }
+        }
+        else
+        {
+            if ( reg != null )
+            {
+                reg.unregister();
+                reg = null;
+            }
+        }
+    }
+    
+    /* (non-Javadoc)
+     * @see org.apache.felix.scr.impl.ScrInfo#list(java.lang.String, 
java.io.PrintStream, java.io.PrintStream)
+     */
+    public void list(final String bundleIdentifier, final PrintWriter out)
+    {
+        List<ComponentDescriptionDTO> components;
+
+        if (bundleIdentifier != null)
+        {
+            Bundle bundle = null;
+            try
+            {
+                long bundleId = Long.parseLong(bundleIdentifier);
+                bundle = bundleContext.getBundle(bundleId);
+            }
+            catch (NumberFormatException nfe)
+            {
+                // might be a bundle symbolic name
+                Bundle[] bundles = bundleContext.getBundles();
+                for (int i = 0; i < bundles.length; i++)
+                {
+                    if (bundleIdentifier.equals(bundles[i].getSymbolicName()))
+                    {
+                        bundle = bundles[i];
+                        break;
+                    }
+                }
+            }
+
+            if (bundle == null)
+            {
+                throw new IllegalArgumentException("Missing bundle with ID " + 
bundleIdentifier);
+            }
+            if (ComponentRegistry.isBundleActive(bundle))
+            {
+                components = new 
ArrayList<ComponentDescriptionDTO>(scrService.getComponentDescriptionDTOs(bundle));
+                if (components.isEmpty())
+                {
+                    out.println("Bundle " + bundleIdentifier + " declares no 
components");
+                    return;
+                }
+            }
+            else
+            {
+                out.println("Bundle " + bundleIdentifier + " is not active");
+                return;
+            }
+        }
+        else
+        {
+            components = new 
ArrayList<ComponentDescriptionDTO>(scrService.getComponentDescriptionDTOs());
+            if (components.isEmpty())
+            {
+                out.println("No components registered");
+                return;
+            }
+        }
+
+        Collections.sort( components, new Comparator<ComponentDescriptionDTO>()
+                {
+
+                    public int compare(ComponentDescriptionDTO c1, 
ComponentDescriptionDTO c2)
+                    {
+                        return c1.name.compareTo(c2.name);
+                    }
+
+                });
+
+        out.println(" Name  BundleId DefaultEnabled");
+        for ( ComponentDescriptionDTO component : components )
+        {
+            out.println( String.format( "[%1$s] [%2$4d] [%3$b]", 
component.name, component.bundle.id, component.defaultEnabled ) );
+        }
+        out.flush();
+   }
+
+    /* (non-Javadoc)
+     * @see org.apache.felix.scr.impl.ScrInfo#info(java.lang.String, 
java.io.PrintStream, java.io.PrintStream)
+     */
+    public void info(final String componentId, PrintWriter out)
+    {
+        Collection<ComponentDescriptionDTO> components = 
getComponentFromArg(componentId);
+        if (components == null)
+        {
+            return;
+        }
+
+        Collections.sort( new ArrayList<ComponentDescriptionDTO>(components), 
new Comparator<ComponentDescriptionDTO>()
+                {
+
+                    public int compare(ComponentDescriptionDTO c1, 
ComponentDescriptionDTO c2)
+                    {
+                        long bundleId1 = c1.bundle.id;
+                        long bundleId2 = c2.bundle.id;
+                        int result = Long.signum(bundleId1 - bundleId2);
+                        if ( result == 0)
+                        {
+                            result = c1.name.compareTo(c2.name);
+                        }
+                        return result;
+                    }
+
+                });
+
+        long bundleId = -1;
+
+        for ( ComponentDescriptionDTO component : components )
+        {
+            if ( component.bundle.id != bundleId )
+            {
+                if ( bundleId != -1 )
+                {
+                    out.println();
+                    out.println();
+                }
+                bundleId = component.bundle.id;
+                out.println(String.format("*** Bundle: %1$s (%2$d)", 
component.bundle.symbolicName, bundleId));
+            }
+            out.println( "Component Description:");
+            out.print( "  Name: " );
+            out.println( component.name );
+            out.print( "  Default State: " );
+            out.println( component.defaultEnabled ? "enabled" : "disabled" );
+            out.print( "  Activation: " );
+            out.println( component.immediate ? "immediate" : "delayed" );
+
+            // DS 1.1 new features
+            out.print( "  Configuration Policy: " );
+            out.println( component.configurationPolicy );
+            out.print( "  Activate Method: " );
+            out.print( component.activate );
+            out.println();
+            out.print( "  Deactivate Method: " );
+            out.print( component.deactivate );
+            out.println();
+            out.print( "  Modified Method: " );
+            if ( component.modified != null )
+            {
+                out.print( component.modified );
+            }
+            else
+            {
+                out.print( "-" );
+            }
+            out.println();
+
+            out.print( "  Configuration Pid: " );
+            out.print( Arrays.asList(component.configurationPid) );
+            out.println();
+
+            if ( component.factory != null )
+            {
+                out.print( "  Factory: " );
+                out.println( component.factory );
+            }
+
+            String[] services = component.serviceInterfaces;
+            if ( services != null )
+            {
+                out.print( "  Services: " );
+                for ( String service: services )
+                {
+                    out.print( "          " );
+                    out.println( service );
+                }
+                out.print( "  Service Scope: " );
+                out.println( component.scope );
+            }
+
+            ReferenceDTO[] refs = component.references;
+            if ( refs != null )
+            {
+                for ( ReferenceDTO ref : refs )
+                {
+                    out.print( "  Reference: " );
+                    out.println( ref.name );
+                    out.print( "    Interface Name: " );
+                    out.println( ref.interfaceName );
+                    if ( ref.target != null )
+                    {
+                        out.print( "    Target Filter: " );
+                        out.println( ref.target );
+                    }
+                    out.print( "    Cardinality: " );
+                    out.println( ref.cardinality );
+                    out.print( "    Policy: " );
+                    out.println( ref.policy );
+                    out.print( "    Policy option: " );
+                    out.println( ref.policyOption );
+                    out.print( "    Reference Scope: ");
+                    out.println( ref.scope);
+
+                }
+            }
+
+            Map<String, Object> props = component.properties;
+            propertyInfo(props, out, "");
+            for (ComponentConfigurationDTO cc: 
scrService.getComponentConfigurationDTOs(component))
+            {
+                info(cc, out);
+            }
+        }
+
+        out.flush();
+    }
+
+    void propertyInfo(Map<String, Object> props, PrintWriter out, String 
prefix)
+    {
+        if ( props != null )
+        {
+            out.print( prefix );
+            out.println( "  Properties:" );
+            TreeMap<String, Object> keys = new TreeMap<String, Object>( props 
);
+            for ( Entry<String, Object> entry: keys.entrySet() )
+            {
+                out.print( prefix );
+                out.print( "    " );
+                out.print( entry.getKey() );
+                out.print( " = " );
+
+                Object prop = entry.getValue();
+                if ( prop.getClass().isArray() )
+                {
+                    out.print("[");
+                    int length = Array.getLength(prop);
+                    for (int i = 0; i< length; i++)
+                    {
+                        out.print(Array.get(prop, i));
+                        if ( i < length - 1)
+                        {
+                            out.print(", ");
+                        }
+                    }
+                    out.println("]");
+                }
+                else
+                {
+                    out.println( prop );
+                }
+            }
+        }
+    }
+
+    private void info(ComponentConfigurationDTO cc, PrintWriter out)
+    {
+        out.println( "  Component Configuration:");
+        out.print("    ComponentId: ");
+        out.println( cc.id );
+        out.print("    State: ");
+        out.println( toStateString(cc.state));
+        for ( SatisfiedReferenceDTO ref: cc.satisfiedReferences)
+        {
+            out.print( "    SatisfiedReference: ");
+            out.println( ref.name );
+            out.print( "      Target: " );
+            out.println( ref.target );
+            ServiceReferenceDTO[] serviceRefs = ref.boundServices;
+            if ( serviceRefs != null )
+            {
+                out.print( "      Bound to:" );
+                for ( ServiceReferenceDTO sr: serviceRefs )
+                {
+                    out.print( "        " );
+                    out.println( sr.id );
+                    propertyInfo(sr.properties, out, "        ");
+                }
+            }
+            else
+            {
+                out.println( "      (unbound)" );
+            }
+
+        }
+        for ( UnsatisfiedReferenceDTO ref: cc.unsatisfiedReferences)
+        {
+            out.print( "    UnsatisfiedReference: ");
+            out.println( ref.name );
+            out.print( "      Target: " );
+            out.println( ref.target );
+            ServiceReferenceDTO[] serviceRefs = ref.targetServices;
+            if ( serviceRefs != null )
+            {
+                out.print( "      Target services:" );
+                for ( ServiceReferenceDTO sr: serviceRefs )
+                {
+                    out.print( "        " );
+                    out.println( sr.id );
+                }
+            }
+            else
+            {
+                out.println( "      (unbound)" );
+            }
+
+        }
+        propertyInfo( cc.properties, out, "    ");
+    }
+
+    void change(final String componentIdentifier, PrintWriter out, boolean 
enable)
+    {
+        Collection<ComponentDescriptionDTO> components = 
getComponentFromArg(componentIdentifier);
+        ArrayList<String> disposed = new ArrayList<String>();
+        if (components == null)
+        {
+            return;
+        }
+
+        for ( ComponentDescriptionDTO component : components )
+        {
+            if ( enable )
+            {
+                if ( !scrService.isComponentEnabled(component) )
+                {
+                    scrService.enableComponent(component);
+                    out.println( "Component " + component.name + " enabled" );
+                }
+                else
+                {
+                    out.println( "Component " + component.name + " already 
enabled" );
+                }
+            }
+            else
+            {
+                if ( scrService.isComponentEnabled(component) )
+                {
+                    scrService.disableComponent(component);
+                    out.println( "Component " + component.name + " disabled" );
+                }
+                else
+                {
+                    out.println( "Component " + component.name + " already 
disabled" );
+                }
+            }
+        }
+        out.flush();
+        if ( !disposed.isEmpty() )
+        {
+            throw new IllegalArgumentException( "Components " + disposed + " 
already disposed, cannot change state" );
+
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.felix.scr.impl.ScrInfo#config(java.io.PrintStream)
+     */
+    public void config(PrintWriter out)
+    {
+        out.print("Log Level: ");
+        out.println(scrConfiguration.getLogLevel());
+        out.print("Obsolete Component Factory with Factory Configuration: ");
+        out.println(scrConfiguration.isFactoryEnabled() ? "Supported" : 
"Unsupported");
+        out.print("Keep instances with no references: ");
+        out.println(scrConfiguration.keepInstances() ? "Supported" : 
"Unsupported");
+        out.print("Lock timeount milliseconds: ");
+        out.println(scrConfiguration.lockTimeout());
+        out.print("Stop timeount milliseconds: ");
+        out.println(scrConfiguration.stopTimeout());
+        out.print("Global extender: ");
+        out.println(scrConfiguration.globalExtender());
+        out.print("Info Service registered: ");
+        out.println(scrConfiguration.infoAsService() ? "Supported" : 
"Unsupported");
+    }
+
+    private String toStateString(int state)
+    {
+        switch (state) {
+
+        case (ComponentConfigurationDTO.UNSATISFIED_REFERENCE):
+            return "unsatisfied reference";
+        case (ComponentConfigurationDTO.ACTIVE):
+            return "active      ";
+        case (ComponentConfigurationDTO.SATISFIED):
+            return "satisfied  ";
+        default:
+            return "unkown: " + state;
+        }
+    }
+
+    private Collection<ComponentDescriptionDTO> getComponentFromArg(final 
String componentIdentifier)
+    {
+        Collection<ComponentDescriptionDTO> components = 
scrService.getComponentDescriptionDTOs();
+        if (componentIdentifier != null)
+        {
+            ArrayList<ComponentDescriptionDTO> cs = new 
ArrayList<ComponentDescriptionDTO>(components.size());
+            Pattern p = Pattern.compile(componentIdentifier);
+            for (ComponentDescriptionDTO component: components)
+            {
+                if ( p.matcher( component.name).matches() )
+                {
+                    cs.add( component );
+                }
+            }
+            if (cs.isEmpty())
+            {
+                throw new IllegalArgumentException("No Component with ID or 
matching " + componentIdentifier);
+            }
+            components = cs;
+        }
+
+        return components;
+    }
+
+}

Added: 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrGogoCommand.java
URL: 
http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrGogoCommand.java?rev=1689973&view=auto
==============================================================================
--- 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrGogoCommand.java
 (added)
+++ 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/ScrGogoCommand.java
 Wed Jul  8 22:10:14 2015
@@ -0,0 +1,130 @@
+/*
+ * 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.PrintWriter;
+
+import org.apache.felix.service.command.Descriptor;
+
+/**
+ * The <code>ScrGogoCommand</code> implements the Apache Felix Gogo Shell
+ * commands for the Apache Felix Declarative Services implementations. 
Supported
+ * commands are:
+ * <dl>
+ * <dt><code>scr:list</code></dt>
+ * <dd>List all components or components of a specific bundle</dd>
+ * <dt><code>scr:info</code></dt>
+ * <dd>Print full information of a single component</dd>
+ * <dt><code>scr:enable</code></dt>
+ * <dd>Enable a component</dd>
+ * <dt><code>scr:disable</code></dt>
+ * <dd>Disable a component</dd>
+ * <dt><code>scr:config</code></dt>
+ * <dd>Print configuration of the Apache Felix Declarative Services bundle</dd>
+ * </dl>
+ * <p>
+ * This class uses Java 5 annotations to provide descriptions for the commands
+ * and arguments. Thus the class must be compiled with Java 5 enabled and thus
+ * the commands will only be available in Java 5 or higher VMs.
+ */
+class ScrGogoCommand
+{
+
+    // The actual implementation of the commands
+    private final ScrCommand scrCommand;
+
+    // this constructor is public to ease the reflection based implementation
+    // See ScrCommand.register for fully disclosure of mechanics
+    public ScrGogoCommand(final ScrCommand scrCommand)
+    {
+        this.scrCommand = scrCommand;
+    }
+
+    @Descriptor("List all components")
+    public void list()
+    {
+        try
+        {
+            scrCommand.list(null, new PrintWriter(System.out));
+        }
+        catch ( IllegalArgumentException e )
+        {
+            System.err.println(e.getMessage());
+        }
+    }
+
+    @Descriptor("List components of a specific bundle")
+    public void list(@Descriptor("Symbolic name or ID of the bundle") final 
String bundleIdentifier)
+    {
+        try
+        {
+            scrCommand.list(bundleIdentifier, new PrintWriter(System.out));
+        }
+        catch ( IllegalArgumentException e )
+        {
+            System.err.println(e.getMessage());
+        }
+    }
+
+    @Descriptor("Dump information of a component")
+    public void info(@Descriptor("Name or ID of the component") final String 
componentIdentifier)
+    {
+        try
+        {
+            scrCommand.info(componentIdentifier, new PrintWriter(System.out));
+        }
+        catch ( IllegalArgumentException e )
+        {
+            System.err.println(e.getMessage());
+        }
+    }
+
+    @Descriptor("Enable a disabled component")
+    public void enable(@Descriptor("Name or ID of the component") final String 
componentIdentifier)
+    {
+        try
+        {
+            scrCommand.change(componentIdentifier, new 
PrintWriter(System.out), true);
+        }
+        catch ( IllegalArgumentException e )
+        {
+            System.err.println(e.getMessage());
+        }
+    }
+
+    @Descriptor("Disable an enabled component")
+    public void disable(@Descriptor("Name or ID of the component") final 
String componentIdentifier)
+    {
+        try
+        {
+            scrCommand.change(componentIdentifier, new 
PrintWriter(System.out), false);
+        }
+        catch ( IllegalArgumentException e )
+        {
+            System.err.println(e.getMessage());
+        }
+    }
+
+    @Descriptor("Show the current SCR configuration")
+    public void config()
+    {
+        scrCommand.config(new PrintWriter(System.out));
+    }
+
+}


Reply via email to