Added: 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
URL: 
http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/AbstractComponentManager.java?rev=1689973&view=auto
==============================================================================
--- 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
 (added)
+++ 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
 Wed Jul  8 22:10:14 2015
@@ -0,0 +1,1389 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr.impl.manager;
+
+import java.lang.reflect.InvocationTargetException;
+import java.security.Permission;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.felix.scr.impl.Activator;
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.config.ComponentContainer;
+import org.apache.felix.scr.impl.config.ComponentManager;
+import org.apache.felix.scr.impl.config.ReferenceManager;
+import org.apache.felix.scr.impl.config.ScrConfiguration;
+import org.apache.felix.scr.impl.helper.ComponentMethods;
+import org.apache.felix.scr.impl.helper.MethodResult;
+import org.apache.felix.scr.impl.helper.SimpleLogger;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
+import org.apache.felix.scr.impl.metadata.ServiceMetadata;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceException;
+import org.osgi.framework.ServicePermission;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.log.LogService;
+import org.osgi.util.promise.Deferred;
+import org.osgi.util.promise.Promise;
+
+
+/**
+ * The default ComponentManager. Objects of this class are responsible for 
managing
+ * implementation object's lifecycle.
+ *
+ */
+public abstract class AbstractComponentManager<S> implements SimpleLogger, 
ComponentManager<S>
+{
+    //useful text for deactivation reason numbers
+    static final String[] REASONS = {"Unspecified",
+        "Component disabled",
+        "Reference became unsatisfied",
+        "Configuration modified",
+        "Configuration deleted",
+        "Component disabled",
+        "Bundle stopped"};
+
+    protected final ComponentContainer<S> m_container;
+
+    //true for normal spec factory instances. False for "persistent" factory 
instances and obsolete use of factory component with factory configurations.
+    protected final boolean m_factoryInstance;
+    // the ID of this component
+    private long m_componentId;
+
+    private final ComponentMethods m_componentMethods;
+
+    // The dependency managers that manage every dependency
+    private final List<DependencyManager<S, ?>> m_dependencyManagers;
+
+    private volatile boolean m_dependencyManagersInitialized;
+
+    private final AtomicInteger m_trackingCount = new AtomicInteger( );
+
+    // The ServiceRegistration is now tracked in the RegistrationManager
+
+    private final ReentrantLock m_stateLock;
+
+    /**
+     * This latch prevents concurrent enable, disable, and reconfigure.  Since 
the enable and disable operations may use
+     * two threads and the initiating thread does not wait for the operation 
to complete, we can't use a regular lock.
+     */
+    private final AtomicReference< Deferred<Void>> m_enabledLatchRef = new 
AtomicReference<Deferred<Void>>( new Deferred<Void>() );
+
+    protected volatile boolean m_internalEnabled;
+
+       private volatile boolean m_satisfied;
+
+    protected volatile boolean m_disposed;
+
+    //service event tracking
+    private int m_floor;
+
+    private volatile int m_ceiling;
+
+    private final Lock m_missingLock = new ReentrantLock();
+    private final Condition m_missingCondition = m_missingLock.newCondition();
+    private final Set<Integer> m_missing = new TreeSet<Integer>( );
+
+    volatile boolean m_activated;
+
+    protected final ReentrantReadWriteLock m_activationLock = new 
ReentrantReadWriteLock();
+
+    /**
+     * The constructor receives both the activator and the metadata
+     *
+     * @param container
+     * @param componentMethods
+     */
+    protected AbstractComponentManager( ComponentContainer<S> container, 
ComponentMethods componentMethods )
+    {
+        this( container, componentMethods, false );
+    }
+
+    protected AbstractComponentManager( ComponentContainer<S> container, 
ComponentMethods componentMethods, boolean factoryInstance )
+    {
+        m_enabledLatchRef.get().resolve(null);
+        m_factoryInstance = factoryInstance;
+        m_container = container;
+        m_componentMethods = componentMethods;
+        m_componentId = -1;
+
+        ComponentMetadata metadata = container.getComponentMetadata();
+
+        m_dependencyManagers = loadDependencyManagers( metadata );
+
+        m_stateLock = new ReentrantLock( true );
+
+        // dump component details
+        if ( isLogEnabled( LogService.LOG_DEBUG ) )
+        {
+            log(
+                LogService.LOG_DEBUG,
+                "Component {0} created: DS={1}, implementation={2}, 
immediate={3}, default-enabled={4}, factory={5}, configuration-policy={6}, 
activate={7}, deactivate={8}, modified={9} configuration-pid={10}",
+                new Object[]
+                    { metadata.getName(), metadata.getDSVersion(),
+                        metadata.getImplementationClassName(), 
metadata.isImmediate(),
+                        metadata.isEnabled(), metadata.getFactoryIdentifier(),
+                        metadata.getConfigurationPolicy(), 
metadata.getActivate(), metadata.getDeactivate(),
+                        metadata.getModified(), metadata.getConfigurationPid() 
}, null );
+
+            if ( metadata.getServiceMetadata() != null )
+            {
+                log( LogService.LOG_DEBUG, "Component {0} Services: scope={1}, 
services={2}", new Object[]
+                    { metadata.getName(), metadata.getServiceScope(),
+                        Arrays.asList( 
metadata.getServiceMetadata().getProvides() ) }, null );
+            }
+
+            if ( metadata.getProperties() != null )
+            {
+                log( LogService.LOG_DEBUG, "Component {0} Properties: {1}", 
new Object[]
+                    { metadata.getName(), metadata.getProperties() }, null );
+            }
+        }
+    }
+
+    final long getLockTimeout()
+    {
+        BundleComponentActivator activator = getActivator();
+        if ( activator != null )
+        {
+            return activator.getConfiguration().lockTimeout();
+        }
+        return ScrConfiguration.DEFAULT_LOCK_TIMEOUT_MILLISECONDS;
+    }
+
+    private void obtainLock( Lock lock, String source )
+    {
+        try
+        {
+            if (!lock.tryLock( getLockTimeout(), TimeUnit.MILLISECONDS ) )
+            {
+                dumpThreads();
+                throw new IllegalStateException( "Could not obtain lock" );
+            }
+        }
+        catch ( InterruptedException e )
+        {
+            try
+            {
+                if (!lock.tryLock( getLockTimeout(), TimeUnit.MILLISECONDS ) )
+                {
+                    dumpThreads();
+                    throw new IllegalStateException( "Could not obtain lock" );
+                }
+            }
+            catch ( InterruptedException e1 )
+            {
+                Thread.currentThread().interrupt();
+                //TODO is there a better exception to throw?
+                throw new IllegalStateException( "Interrupted twice: Could not 
obtain lock" );
+            }
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    final void obtainActivationReadLock( String source )
+    {
+        obtainLock( m_activationLock.readLock(), source);
+    }
+
+    final void releaseActivationReadLock( String source )
+    {
+        m_activationLock.readLock().unlock();
+    }
+
+    final void obtainActivationWriteLock( String source )
+    {
+        obtainLock( m_activationLock.writeLock(), source);
+    }
+
+    final void releaseActivationWriteeLock( String source )
+    {
+        if ( m_activationLock.getWriteHoldCount() > 0 )
+        {
+            m_activationLock.writeLock().unlock();
+        }
+    }
+
+    final void obtainStateLock( String source )
+    {
+        obtainLock( m_stateLock, source );
+    }
+
+    final void releaseStateLock( String source )
+    {
+        m_stateLock.unlock();
+    }
+
+    final boolean isStateLocked()
+    {
+        return m_stateLock.getHoldCount() > 0;
+    }
+
+    final void dumpThreads()
+    {
+        try
+        {
+            String dump = new ThreadDump().call();
+            log( LogService.LOG_DEBUG, dump, null );
+        }
+        catch ( Throwable t )
+        {
+            log( LogService.LOG_DEBUG, "Could not dump threads", t );
+        }
+    }
+
+    //service event tracking
+    void tracked( int trackingCount )
+    {
+        m_missingLock.lock();
+        try
+        {
+            if (trackingCount == m_floor + 1 )
+            {
+                m_floor++;
+                m_missing.remove( trackingCount );
+            }
+            else if ( trackingCount < m_ceiling )
+            {
+                m_missing.remove( trackingCount );
+            }
+            if ( trackingCount > m_ceiling )
+            {
+                for (int i = m_ceiling + 1; i < trackingCount; i++ )
+                {
+                    m_missing.add( i );
+                }
+                m_ceiling = trackingCount;
+            }
+            m_missingCondition.signalAll();
+        }
+        finally
+        {
+            m_missingLock.unlock();
+        }
+    }
+
+    /**
+     * We effectively maintain the set of completely processed service event 
tracking counts.  This method waits for all events prior
+     * to the parameter tracking count to complete, then returns.  See further 
documentation in EdgeInfo.
+     * @param trackingCount
+     */
+    void waitForTracked( int trackingCount )
+    {
+        m_missingLock.lock();
+        try
+        {
+            while ( m_ceiling  < trackingCount || ( !m_missing.isEmpty() && 
m_missing.iterator().next() < trackingCount))
+            {
+                log( LogService.LOG_DEBUG, "waitForTracked trackingCount: {0} 
ceiling: {1} missing: {2}",
+                        new Object[] {trackingCount, m_ceiling, m_missing}, 
null );
+                try
+                {
+                    if ( !doMissingWait())
+                    {
+                        return;
+                    }
+                }
+                catch ( InterruptedException e )
+                {
+                    try
+                    {
+                        if ( !doMissingWait())
+                        {
+                            return;
+                        }
+                    }
+                    catch ( InterruptedException e1 )
+                    {
+                        log( LogService.LOG_ERROR, "waitForTracked interrupted 
twice: {0} ceiling: {1} missing: {2},  Expect further errors",
+                                new Object[] {trackingCount, m_ceiling, 
m_missing}, e1 );
+                    }
+                    Thread.currentThread().interrupt();
+                }
+            }
+        }
+        finally
+        {
+            m_missingLock.unlock();
+        }
+    }
+
+    private boolean doMissingWait() throws InterruptedException
+    {
+        if ( !m_missingCondition.await( getLockTimeout(), 
TimeUnit.MILLISECONDS ))
+        {
+            log( LogService.LOG_ERROR, "waitForTracked timed out: {0} ceiling: 
{1} missing: {2},  Expect further errors",
+                    new Object[] {m_trackingCount, m_ceiling, m_missing}, null 
);
+            dumpThreads();
+            m_missing.clear();
+            return false;
+        }
+        return true;
+    }
+
+//---------- Component ID management
+
+    void registerComponentId()
+    {
+        final BundleComponentActivator activator = getActivator();
+        if ( activator != null )
+        {
+            this.m_componentId = activator.registerComponentId( this );
+        }
+    }
+
+
+    void unregisterComponentId()
+    {
+        if ( this.m_componentId >= 0 )
+        {
+            final BundleComponentActivator activator = getActivator();
+            if ( activator != null )
+            {
+                activator.unregisterComponentId( this );
+            }
+            this.m_componentId = -1;
+        }
+    }
+
+
+    //---------- Asynchronous frontend to state change methods ----------------
+    private static final AtomicLong taskCounter = new AtomicLong( );
+
+    public final Promise<Void> enable( final boolean async )
+    {
+        Deferred<Void> enableLatch = null;
+        try
+        {
+            enableLatch = enableLatchWait();
+            enableInternal();
+            if ( !async )
+            {
+                activateInternal( m_trackingCount.get() );
+            }
+        }
+        finally
+        {
+            if ( !async )
+            {
+                enableLatch.resolve(null);
+            }
+        }
+
+        if ( async )
+        {
+            final Deferred<Void> latch = enableLatch;
+            getActivator().schedule( new Runnable()
+            {
+
+                long count = taskCounter.incrementAndGet();
+
+                public void run()
+                {
+                    try
+                    {
+                        activateInternal( m_trackingCount.get() );
+                    }
+                    finally
+                    {
+                        latch.resolve(null);
+                    }
+                }
+
+                @Override
+                public String toString()
+                {
+                    return "Async Activate: " + 
getComponentMetadata().getName() + " id: " + count;
+                }
+            } );
+        }
+        return enableLatch.getPromise();
+    }
+
+    /**
+     * Use a CountDownLatch as a non-reentrant "lock" that can be passed 
between threads.
+     * This lock assures that enable, disable, and reconfigure operations do 
not overlap.
+     *
+     * @return the latch to count down when the operation is complete (in the 
calling or another thread)
+     * @throws InterruptedException
+     */
+    Deferred<Void> enableLatchWait()
+    {
+        Deferred<Void> enabledLatch;
+        Deferred<Void> newEnabledLatch;
+        do
+        {
+            enabledLatch = m_enabledLatchRef.get();
+            boolean waited = false;
+            boolean interrupted = false;
+            while ( !waited )
+            {
+                try
+                {
+                    enabledLatch.getPromise().getValue();
+                    waited = true;
+                }
+                catch ( InterruptedException e )
+                {
+                    interrupted = true;
+                }
+                catch (InvocationTargetException e)
+                {
+                    //this is not going to happen
+                }
+            }
+            if ( interrupted )
+            {
+                Thread.currentThread().interrupt();
+            }
+            newEnabledLatch = new Deferred<Void>();
+        }
+        while ( !m_enabledLatchRef.compareAndSet( enabledLatch, 
newEnabledLatch) );
+        return newEnabledLatch;
+    }
+
+    public final Promise<Void> disable( final boolean async )
+    {
+        Deferred<Void> enableLatch = null;
+        try
+        {
+            enableLatch = enableLatchWait();
+            if ( !async )
+            {
+                deactivateInternal( 
ComponentConstants.DEACTIVATION_REASON_DISABLED, true, false );
+            }
+            disableInternal();
+        }
+        finally
+        {
+            if (!async)
+            {
+                enableLatch.resolve(null);
+            }
+        }
+
+        if ( async )
+        {
+            final Deferred<Void> latch = enableLatch;
+            getActivator().schedule( new Runnable()
+            {
+
+                long count = taskCounter.incrementAndGet();
+
+                public void run()
+                {
+                    try
+                    {
+                        deactivateInternal( 
ComponentConstants.DEACTIVATION_REASON_DISABLED, true, false );
+                    }
+                    finally
+                    {
+                        latch.resolve(null);
+                    }
+                }
+
+                @Override
+                public String toString()
+                {
+                    return "Async Deactivate: " + 
getComponentMetadata().getName() + " id: " + count;
+                }
+
+            } );
+        }
+        return enableLatch.getPromise();
+    }
+
+    // supports the ComponentInstance.dispose() method
+    void dispose()
+    {
+        dispose( ComponentConstants.DEACTIVATION_REASON_DISPOSED );
+    }
+
+    /**
+     * Disposes off this component deactivating and disabling it first as
+     * required. After disposing off the component, it may not be used anymore.
+     * <p>
+     * This method unlike the other state change methods immediately takes
+     * action and disposes the component. The reason for this is, that this
+     * method has to actually complete before other actions like bundle 
stopping
+     * may continue.
+     */
+    public void dispose( int reason )
+    {
+        deactivateInternal( reason, true, true );
+    }
+
+    <T> void registerMissingDependency( DependencyManager<S, T> dm, 
ServiceReference<T> ref, int trackingCount)
+    {
+        BundleComponentActivator activator = getActivator();
+        if ( activator != null )
+        {
+            activator.registerMissingDependency( dm, ref, trackingCount );
+        }
+    }
+
+    //---------- Component interface ------------------------------------------
+
+    public long getId()
+    {
+        return m_componentId;
+    }
+
+    protected String getName() {
+        return getComponentMetadata().getName();
+    }
+
+    /**
+     * Returns the <code>Bundle</code> providing this component. If the
+     * component as already been disposed off, this method returns
+     * <code>null</code>.
+     */
+    public Bundle getBundle()
+    {
+        final BundleContext context = getBundleContext();
+        if ( context != null )
+        {
+            try
+            {
+                return context.getBundle();
+            }
+            catch ( IllegalStateException ise )
+            {
+                // if the bundle context is not valid any more
+            }
+        }
+        // already disposed off component or bundle context is invalid
+        return null;
+    }
+
+    BundleContext getBundleContext()
+    {
+        final BundleComponentActivator activator = getActivator();
+        if ( activator != null )
+        {
+            return activator.getBundleContext();
+        }
+        return null;
+    }
+
+
+    protected boolean isImmediate()
+    {
+        return getComponentMetadata().isImmediate();
+
+    }
+
+    public boolean isFactory()
+    {
+        return false;
+    }
+
+    protected boolean isSatisfied()
+    {
+        return m_satisfied;
+    }
+
+
+    //-------------- atomic transition methods -------------------------------
+
+    final void enableInternal()
+    {
+        if ( m_disposed )
+        {
+            throw new IllegalStateException( "enable: " + this );
+        }
+        if ( !isActivatorActive() )
+        {
+            log( LogService.LOG_DEBUG, "Bundle's component activator is not 
active; not enabling component",
+                    null );
+            return;
+        }
+
+        registerComponentId();
+        log( LogService.LOG_DEBUG, "Updating target filters", null );
+        updateTargets( getProperties() );
+
+        m_internalEnabled = true;
+        log( LogService.LOG_DEBUG, "Component enabled", null );
+    }
+
+    final void activateInternal( int trackingCount )
+    {
+        log( LogService.LOG_DEBUG, "ActivateInternal",
+                null );
+        if ( m_disposed )
+        {
+            log( LogService.LOG_DEBUG, "ActivateInternal: disposed",
+                    null );
+            return;
+        }
+        if ( m_activated ) {
+            log( LogService.LOG_DEBUG, "ActivateInternal: already activated",
+                    null );
+            return;
+        }
+        if ( !isInternalEnabled())
+        {
+            log( LogService.LOG_DEBUG, "Component is not enabled; not 
activating component",
+                    null );
+            return;
+        }
+        if ( !isActivatorActive() )
+        {
+            log( LogService.LOG_DEBUG, "Bundle's component activator is not 
active; not activating component",
+                    null );
+            return;
+        }
+
+        log( LogService.LOG_DEBUG, "Activating component from state {0}", new 
Object[] {getState()},  null );
+
+        // Before creating the implementation object, we are going to
+        // test that the bundle has enough permissions to register services
+        if ( !hasServiceRegistrationPermissions() )
+        {
+            log( LogService.LOG_DEBUG, "Component is not permitted to register 
all services, cannot activate",
+                    null );
+            return;
+        }
+
+        obtainActivationReadLock( "activateInternal" );
+        try
+        {
+            // Double check conditions now that we have obtained the lock
+            if ( m_disposed )
+            {
+                log( LogService.LOG_DEBUG, "ActivateInternal: disposed",
+                        null );
+                return;
+            }
+            if ( m_activated ) {
+                log( LogService.LOG_DEBUG, "ActivateInternal: already 
activated",
+                        null );
+                return;
+            }
+            if ( !isInternalEnabled() )
+            {
+                log( LogService.LOG_DEBUG, "Component is not enabled; not 
activating component",
+                        null );
+                return;
+            }
+            // Before creating the implementation object, we are going to
+            // test if all the mandatory dependencies are satisfied
+            if ( !verifyDependencyManagers() )
+            {
+                log( LogService.LOG_DEBUG, "Not all dependencies satisfied, 
cannot activate", null );
+                return;
+            }
+
+            if ( !registerService() )
+            {
+                //some other thread is activating us, or we got concurrently 
deactivated.
+                return;
+            }
+
+
+            if ( ( isImmediate() || getComponentMetadata().isFactory() ) )
+            {
+                getServiceInternal();
+            }
+        }
+        finally
+        {
+            releaseActivationReadLock( "activateInternal" );
+        }
+    }
+
+    /**
+     * Handles deactivating, disabling, and disposing a component manager. 
Deactivating a factory instance
+     * always disables and disposes it.  Deactivating a factory disposes it.
+     * @param reason reason for action
+     * @param disable whether to also disable the manager
+     * @param dispose whether to also dispose of the manager
+     */
+    final void deactivateInternal( int reason, boolean disable, boolean 
dispose )
+    {
+        synchronized ( this )
+        {
+            if ( m_disposed )
+            {
+                return;
+            }
+            m_disposed = dispose;
+        }
+        log( LogService.LOG_DEBUG, "Deactivating component", null );
+
+        // catch any problems from deleting the component to prevent the
+        // component to remain in the deactivating state !
+        obtainActivationReadLock( "deactivateInternal" );
+        try
+        {
+            doDeactivate( reason, disable || m_factoryInstance );
+        }
+        finally
+        {
+            releaseActivationReadLock( "deactivateInternal" );
+        }
+        if ( isFactory() || m_factoryInstance || dispose )
+        {
+            log( LogService.LOG_DEBUG, "Disposing component (reason: " + 
reason + ")", null );
+            clear();
+        }
+    }
+
+    private void doDeactivate( int reason, boolean disable )
+    {
+        try
+        {
+            if ( !unregisterService() )
+            {
+                log( LogService.LOG_DEBUG, "Component deactivation occuring on 
another thread", null );
+            }
+            obtainStateLock( "AbstractComponentManager.State.doDeactivate.1" );
+            try
+            {
+               m_satisfied = false;
+                m_activated = false;
+                deleteComponent( reason );
+                deactivateDependencyManagers();
+                if ( disable )
+                {
+                    disableDependencyManagers();
+                }
+            }
+            finally
+            {
+                releaseStateLock( 
"AbstractComponentManager.State.doDeactivate.1" );
+            }
+        }
+        catch ( Throwable t )
+        {
+            log( LogService.LOG_WARNING, "Component deactivation threw an 
exception", t );
+        }
+    }
+
+    final void disableInternal()
+    {
+        m_internalEnabled = false;
+        if ( m_disposed )
+        {
+            throw new IllegalStateException( "Cannot disable a disposed 
component " + getName() );
+        }
+        unregisterComponentId();
+    }
+
+    final ServiceReference<S> getServiceReference()
+    {
+        ServiceRegistration<S> reg = getServiceRegistration();
+        if (reg != null)
+        {
+            return reg.getReference();
+        }
+        return null;
+    }
+
+    //---------- Component handling methods ----------------------------------
+
+    protected abstract void deleteComponent( int reason );
+
+    boolean getServiceInternal()
+    {
+        return false;
+    }
+
+    /**
+     * All ComponentManagers are ServiceFactory instances
+     *
+     * @return this as a ServiceFactory.
+     */
+    private Object getService()
+    {
+        return this;
+    }
+
+    ComponentMethods getComponentMethods()
+    {
+        return m_componentMethods;
+    }
+
+    protected String[] getProvidedServices()
+    {
+        if ( getComponentMetadata().getServiceMetadata() != null )
+        {
+            String[] provides = 
getComponentMetadata().getServiceMetadata().getProvides();
+            return provides;
+        }
+        return null;
+
+    }
+
+    private final RegistrationManager<ServiceRegistration<S>> 
registrationManager = new RegistrationManager<ServiceRegistration<S>>()
+    {
+
+        @Override
+        ServiceRegistration<S> register(String[] services)
+        {
+            BundleContext bundleContext = getBundleContext();
+            if (bundleContext == null)
+            {
+                return null;
+            }
+            final Dictionary<String, Object> serviceProperties = 
getServiceProperties();
+            try {
+                               ServiceRegistration<S> serviceRegistration = 
(ServiceRegistration<S>) bundleContext
+                                               .registerService(services, 
getService(),
+                                                               
serviceProperties);
+                               return serviceRegistration;
+                       } catch (ServiceException e) {
+                               log(LogService.LOG_ERROR, "Unexpected error 
registering component service with properties {0}",
+                                               new Object[] 
{serviceProperties}, e);
+                               return null;
+                       }
+        }
+
+        @Override
+        void unregister(ServiceRegistration<S> serviceRegistration)
+        {
+            serviceRegistration.unregister();
+        }
+
+        @Override
+        void log(int level, String message, Object[] arguments, Throwable ex)
+        {
+            AbstractComponentManager.this.log(level, message, arguments, ex);
+        }
+
+        @Override
+        long getTimeout()
+        {
+            return getLockTimeout();
+        }
+
+        @Override
+        void reportTimeout()
+        {
+            dumpThreads();
+        }
+
+    };
+
+    /**
+     * Registers the service on behalf of the component.
+     *
+     */
+    protected boolean registerService()
+    {
+        String[] services = getProvidedServices();
+        if ( services != null )
+        {
+            return registrationManager.changeRegistration( 
RegistrationManager.RegState.registered, services);
+        }
+        return true;
+    }
+
+    protected boolean unregisterService()
+    {
+        String[] services = getProvidedServices();
+        if ( services != null )
+        {
+            return registrationManager.changeRegistration( 
RegistrationManager.RegState.unregistered, services );
+        }
+        return true;
+    }
+
+
+    AtomicInteger getTrackingCount()
+    {
+        return m_trackingCount;
+    }
+
+
+    private void initDependencyManagers()
+    {
+        if ( m_dependencyManagersInitialized )
+        {
+            return;
+        }
+        final Bundle bundle = getBundle();
+        if (bundle == null)
+        {
+            log( LogService.LOG_ERROR, "bundle shut down while trying to load 
implementation object class", null );
+            throw new IllegalStateException("bundle shut down while trying to 
load implementation object class");
+        }
+        Class<?> implementationObjectClass;
+        try
+        {
+            implementationObjectClass = bundle.loadClass(
+                    getComponentMetadata().getImplementationClassName() );
+        }
+        catch ( ClassNotFoundException e )
+        {
+            log( LogService.LOG_ERROR, "Could not load implementation object 
class {0}",
+                    new Object[] 
{getComponentMetadata().getImplementationClassName()}, e );
+            throw new IllegalStateException("Could not load implementation 
object class "
+                    + getComponentMetadata().getImplementationClassName());
+        }
+        m_componentMethods.initComponentMethods( getComponentMetadata(), 
implementationObjectClass );
+
+        for ( DependencyManager dependencyManager : m_dependencyManagers )
+        {
+            dependencyManager.initBindingMethods( 
m_componentMethods.getBindMethods( dependencyManager.getName() ) );
+        }
+        m_dependencyManagersInitialized = true;
+    }
+
+    /**
+     * Collect and store in m_dependencies_map all the services for 
dependencies, outside of any locks.
+     * @param componentContext possible instance key for prototype scope 
references
+     *
+     * @return true if all references can be collected,
+     *   false if some dependency is no longer available.
+     */
+    protected boolean collectDependencies(ComponentContextImpl<S> 
componentContext)
+    {
+        initDependencyManagers();
+        for ( DependencyManager<S, ?> dependencyManager : m_dependencyManagers 
)
+        {
+            if ( !dependencyManager.prebind(componentContext) )
+            {
+                //not actually satisfied any longer
+                deactivateDependencyManagers();
+                log( LogService.LOG_DEBUG, "Could not get required dependency 
for dependency manager: {0}",
+                        new Object[] {dependencyManager.getName()}, null );
+                return false;
+            }
+        }
+        log( LogService.LOG_DEBUG, "This thread collected dependencies", null 
);
+        return true;
+    }
+
+    abstract <T> void invokeUpdatedMethod( DependencyManager<S, T> 
dependencyManager, RefPair<S, T> refPair, int trackingCount );
+
+    abstract <T> void invokeBindMethod( DependencyManager<S, T> 
dependencyManager, RefPair<S, T> refPair, int trackingCount );
+
+    abstract <T> void invokeUnbindMethod( DependencyManager<S, T> 
dependencyManager, RefPair<S, T> oldRefPair, int trackingCount );
+
+    
//**********************************************************************************************************
+    public BundleComponentActivator getActivator()
+    {
+        return m_container.getActivator();
+    }
+
+
+    boolean isActivatorActive()
+    {
+        BundleComponentActivator activator = getActivator();
+        return activator != null && activator.isActive();
+    }
+
+
+    final ServiceRegistration<S> getServiceRegistration()
+    {
+        return registrationManager.getServiceRegistration();
+    }
+
+
+    synchronized void clear()
+    {
+        // for some testing, the activator may be null
+        if ( m_container.getActivator() != null )
+        {
+            m_container.getActivator().unregisterComponentId( this );
+        }
+    }
+
+    /**
+     * Returns <code>true</code> if logging for the given level is enabled.
+     */
+    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(), 
m_componentId, ex );
+        }
+    }
+
+    public void log( int level, String message, Object[] arguments, Throwable 
ex )
+    {
+        BundleComponentActivator activator = getActivator();
+        if ( activator != null )
+        {
+            activator.log( level, message, arguments, getComponentMetadata(), 
m_componentId, ex );
+        }
+    }
+
+
+    @Override
+    public String toString()
+    {
+        return "Component: " + getName() + " (" + getId() + ")";
+    }
+
+
+    private boolean hasServiceRegistrationPermissions()
+    {
+        boolean allowed = true;
+        if ( System.getSecurityManager() != null )
+        {
+            final ServiceMetadata serviceMetadata = 
getComponentMetadata().getServiceMetadata();
+            if ( serviceMetadata != null )
+            {
+                final String[] services = serviceMetadata.getProvides();
+                if ( services != null && services.length > 0 )
+                {
+                    final Bundle bundle = getBundle();
+                    for ( String service : services )
+                    {
+                        final Permission perm = new ServicePermission( 
service, ServicePermission.REGISTER );
+                        if ( !bundle.hasPermission( perm ) )
+                        {
+                            log( LogService.LOG_DEBUG, "Permission to register 
service {0} is denied", new Object[]
+                                    {service}, null );
+                            allowed = false;
+                        }
+                    }
+                }
+            }
+        }
+
+        // no security manager or no services to register
+        return allowed;
+    }
+
+
+    private List<DependencyManager<S, ?>> loadDependencyManagers( 
ComponentMetadata metadata )
+    {
+        List<DependencyManager<S, ?>> depMgrList = new 
ArrayList<DependencyManager<S, ?>>(metadata.getDependencies().size());
+
+        // If this component has got dependencies, create dependency managers 
for each one of them.
+        if ( metadata.getDependencies().size() != 0 )
+        {
+            int index = 0;
+            for ( ReferenceMetadata currentdependency: 
metadata.getDependencies() )
+            {
+                DependencyManager<S, ?> depmanager = new DependencyManager( 
this, currentdependency, index++ );
+
+                depMgrList.add( depmanager );
+            }
+        }
+
+        return depMgrList;
+    }
+
+    final void updateTargets(Map<String, Object> properties)
+    {
+        for ( DependencyManager<S, ?> dm: getDependencyManagers() )
+        {
+            dm.setTargetFilter( properties );
+        }
+    }
+
+    protected boolean verifyDependencyManagers()
+    {
+        // indicates whether all dependencies are satisfied
+        boolean satisfied = true;
+
+        for ( DependencyManager<S, ?> dm: getDependencyManagers() )
+        {
+
+            if ( !dm.hasGetPermission() )
+            {
+                // bundle has no service get permission
+                if ( dm.isOptional() )
+                {
+                    log( LogService.LOG_DEBUG, "No permission to get optional 
dependency: {0}; assuming satisfied",
+                        new Object[]
+                            { dm.getName() }, null );
+                }
+                else
+                {
+                    log( LogService.LOG_DEBUG, "No permission to get mandatory 
dependency: {0}; assuming unsatisfied",
+                        new Object[]
+                            { dm.getName() }, null );
+                    satisfied = false;
+                }
+            }
+            else if ( !dm.isSatisfied() )
+            {
+                // bundle would have permission but there are not enough 
services
+                log( LogService.LOG_DEBUG, "Dependency not satisfied: {0}", 
new Object[]
+                    { dm.getName() }, null );
+                satisfied = false;
+            }
+        }
+
+        m_satisfied = satisfied;
+        return satisfied;
+    }
+
+    /**
+     * Returns an iterator over the {@link DependencyManager} objects
+     * representing the declared references in declaration order
+     */
+    List<DependencyManager<S, ?>> getDependencyManagers()
+    {
+        return m_dependencyManagers;
+    }
+
+    public List<? extends ReferenceManager<S, ?>> getReferenceManagers()
+    {
+       return m_dependencyManagers;
+    }
+
+    /**
+     * Returns an iterator over the {@link DependencyManager} objects
+     * representing the declared references in reversed declaration order
+     */
+    List<DependencyManager<S, ?>> getReversedDependencyManagers()
+    {
+        List<DependencyManager<S, ?>> list = new 
ArrayList<DependencyManager<S, ?>>( m_dependencyManagers );
+        Collections.reverse( list );
+        return list;
+    }
+
+
+    DependencyManager<S, ?> getDependencyManager(String name)
+    {
+        for ( ReferenceManager<S, ?> dm: getDependencyManagers() )
+        {
+            if ( name.equals(dm.getName()) )
+            {
+                return (DependencyManager<S, ?>) dm;
+            }
+        }
+
+        // not found
+        return null;
+    }
+
+    private void deactivateDependencyManagers()
+    {
+        log( LogService.LOG_DEBUG, "Deactivating dependency managers", null);
+        for ( DependencyManager<S, ?> dm: getDependencyManagers() )
+        {
+            dm.deactivate();
+        }
+    }
+
+    private void disableDependencyManagers()
+    {
+        log( LogService.LOG_DEBUG, "Disabling dependency managers", null);
+        AtomicInteger trackingCount = new AtomicInteger();
+        for ( DependencyManager<S, ?> dm: getDependencyManagers() )
+        {
+            dm.unregisterServiceListener( trackingCount );
+        }
+    }
+
+    /* (non-Javadoc)
+        * @see 
org.apache.felix.scr.impl.manager.ComponentManager#getProperties()
+        */
+    public abstract Map<String, Object> getProperties();
+
+    public abstract void setServiceProperties( Dictionary<String, ?> 
serviceProperties );
+
+    /**
+     * Returns the subset of component properties to be used as service
+     * properties. These properties are all component properties where property
+     * name does not start with dot (.), properties which are considered
+     * private.
+     */
+    public Dictionary<String, Object> getServiceProperties()
+    {
+        return copyTo( null, getProperties(), false );
+    }
+
+    /**
+     * Copies the properties from the <code>source</code> 
<code>Dictionary</code>
+     * into the <code>target</code> <code>Dictionary</code> except for private
+     * properties (whose name has a leading dot) which are only copied if the
+     * <code>allProps</code> parameter is <code>true</code>.
+     *
+     * @param target    The <code>Dictionary</code> into which to copy the
+     *                  properties. If <code>null</code> a new 
<code>Hashtable</code> is
+     *                  created.
+     * @param source    The <code>Dictionary</code> providing the properties to
+     *                  copy. If <code>null</code> or empty, nothing is copied.
+     * @param allProps  Whether all properties (<code>true</code>) or only the
+     *                  public properties (<code>false</code>) are to be 
copied.
+     *
+     * @return The <code>target</code> is returned, which may be empty if
+     *         <code>source</code> is <code>null</code> or empty and
+     *         <code>target</code> was <code>null</code> or all properties are
+     *         private and had not to be copied
+     */
+    protected static Dictionary<String, Object> copyTo( Dictionary<String, 
Object> target, final Map<String, ?> source, final boolean allProps )
+    {
+        if ( target == null )
+        {
+            target = new Hashtable<String, Object>();
+        }
+
+        if ( source != null && !source.isEmpty() )
+        {
+            for ( Map.Entry<String, ?> entry: source.entrySet() )
+            {
+                // cast is save, because key must be a string as per the spec
+                String key = entry.getKey();
+                if ( allProps || key.charAt( 0 ) != '.' )
+                {
+                    target.put( key, entry.getValue() );
+                }
+            }
+        }
+
+        return target;
+    }
+
+    /**
+     * Copies the properties from the <code>source</code> 
<code>Dictionary</code>
+     * into the <code>target</code> <code>Dictionary</code> except for private
+     * properties (whose name has a leading dot) which are only copied if the
+     * <code>allProps</code> parameter is <code>true</code>.
+     * @param source    The <code>Dictionary</code> providing the properties to
+     *                  copy. If <code>null</code> or empty, nothing is copied.
+     * @param allProps  Whether all properties (<code>true</code>) or only the
+     *                  public properties (<code>false</code>) are to be 
copied.
+     *
+     * @return The <code>target</code> is returned, which may be empty if
+     *         <code>source</code> is <code>null</code> or empty and
+     *         <code>target</code> was <code>null</code> or all properties are
+     *         private and had not to be copied
+     */
+    protected static Map<String, Object> copyToMap( final Dictionary<String, 
?> source, final boolean allProps )
+    {
+        Map<String, Object> target = new HashMap<String, Object>();
+
+        if ( source != null && !source.isEmpty() )
+        {
+            for ( Enumeration<String> ce = source.keys(); 
ce.hasMoreElements(); )
+            {
+                // cast is save, because key must be a string as per the spec
+                String key = ce.nextElement();
+                if ( allProps || key.charAt( 0 ) != '.' )
+                {
+                    target.put( key, source.get( key ) );
+                }
+            }
+        }
+
+        return target;
+    }
+
+    protected static Dictionary<String, Object> copyToDictionary( final 
Dictionary<String, ?> source, final boolean allProps )
+    {
+        Hashtable<String, Object> target = new Hashtable<String, Object>();
+
+        if ( source != null && !source.isEmpty() )
+        {
+            for ( Enumeration<String> ce = source.keys(); 
ce.hasMoreElements(); )
+            {
+                // cast is save, because key must be a string as per the spec
+                String key = ce.nextElement();
+                if ( allProps || key.charAt( 0 ) != '.' )
+                {
+                    target.put( key, source.get( key ) );
+                }
+            }
+        }
+
+        return target;
+    }
+
+
+    /**
+     *
+     */
+    public ComponentMetadata getComponentMetadata()
+    {
+        return m_container.getComponentMetadata();
+    }
+
+    /**
+     * TODO now returning bizarre mix of values!!
+     */
+    public int getState()
+    {
+        if (m_disposed)
+        {
+            return STATE_DISPOSED;
+        }
+        if ( !m_internalEnabled)
+        {
+            return STATE_DISABLED;
+        }
+        if ( !m_satisfied )
+        {
+            return STATE_UNSATISFIED_REFERENCE;
+        }
+        if ( hasInstance() )
+        {
+            return STATE_ACTIVE;
+        }
+        return STATE_SATISFIED;
+    }
+
+    abstract boolean hasInstance();
+
+    public void setServiceProperties( MethodResult methodResult )
+    {
+        if ( methodResult.hasResult() )
+        {
+            Dictionary<String, Object> serviceProps = ( 
methodResult.getResult() == null) ? null : new Hashtable<String, Object>( 
methodResult.getResult() );
+            setServiceProperties(serviceProps );
+        }
+    }
+
+    boolean isInternalEnabled()
+    {
+        return m_internalEnabled;
+    }
+
+       public abstract void reconfigure(Map<String, Object> configuration, 
boolean configurationDeleted);
+
+       public abstract void 
getComponentManagers(List<AbstractComponentManager<S>> cms);
+
+}

Added: 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ComponentContextImpl.java
URL: 
http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ComponentContextImpl.java?rev=1689973&view=auto
==============================================================================
--- 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ComponentContextImpl.java
 (added)
+++ 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ComponentContextImpl.java
 Wed Jul  8 22:10:14 2015
@@ -0,0 +1,269 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr.impl.manager;
+
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.felix.scr.component.ExtComponentContext;
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.helper.ComponentServiceObjectsHelper;
+import org.apache.felix.scr.impl.helper.ReadOnlyDictionary;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceObjects;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentInstance;
+import org.osgi.service.log.LogService;
+
+
+/**
+ * Implementation for the ComponentContext interface
+ *
+ */
+public class ComponentContextImpl<S> implements ExtComponentContext {
+
+    private final SingleComponentManager<S> m_componentManager;
+
+    private final EdgeInfo[] edgeInfos;
+
+    private final ComponentInstance m_componentInstance = new 
ComponentInstanceImpl<S>(this);
+
+    private final Bundle m_usingBundle;
+
+    private volatile S m_implementationObject;
+
+    private volatile boolean m_implementationAccessible;
+
+    private final CountDownLatch accessibleLatch = new CountDownLatch(1);
+
+    private final ComponentServiceObjectsHelper serviceObjectsHelper;
+
+    public ComponentContextImpl( final SingleComponentManager<S> 
componentManager, final Bundle usingBundle )
+    {
+        m_componentManager = componentManager;
+        m_usingBundle = usingBundle;
+        edgeInfos = new 
EdgeInfo[componentManager.getComponentMetadata().getDependencies().size()];
+        for (int i = 0; i< edgeInfos.length; i++)
+        {
+            edgeInfos[i] = new EdgeInfo();
+        }
+        this.serviceObjectsHelper = new 
ComponentServiceObjectsHelper(usingBundle.getBundleContext());
+    }
+
+    public void cleanup()
+    {
+        this.serviceObjectsHelper.cleanup();
+    }
+
+    public ComponentServiceObjectsHelper getComponentServiceObjectsHelper()
+    {
+        return this.serviceObjectsHelper;
+    }
+
+    public void setImplementationObject(S implementationObject)
+    {
+        this.m_implementationObject = implementationObject;
+    }
+
+
+    void setImplementationAccessible(boolean implementationAccessible)
+    {
+        this.m_implementationAccessible = implementationAccessible;
+        if (implementationAccessible)
+        {
+            accessibleLatch.countDown();
+        }
+    }
+
+    EdgeInfo getEdgeInfo(DependencyManager<S, ?> dm)
+    {
+        int index = dm.getIndex();
+        return edgeInfos[index];
+    }
+
+   protected SingleComponentManager<S> getComponentManager()
+    {
+        return m_componentManager;
+    }
+
+    public final Dictionary<String, Object> getProperties()
+    {
+        // 112.12.3.5 The Dictionary is read-only and cannot be modified
+        return new ReadOnlyDictionary<String, Object>( 
m_componentManager.getProperties() );
+    }
+
+
+    public Object locateService( String name )
+    {
+        m_componentManager.obtainActivationReadLock( "locate.service.name" );
+        try
+        {
+            DependencyManager<S, ?> dm = 
m_componentManager.getDependencyManager( name );
+            return ( dm != null ) ? dm.getService(this) : null;
+        }
+        finally
+        {
+            m_componentManager.releaseActivationReadLock( 
"locate.service.name" );
+        }
+    }
+
+
+    public Object locateService( String name, ServiceReference ref )
+    {
+        m_componentManager.obtainActivationReadLock( "locate.service.ref" );
+        try
+        {
+            DependencyManager<S, ?> dm = 
m_componentManager.getDependencyManager( name );
+            return ( dm != null ) ? dm.getService( this, ref ) : null;
+        }
+        finally
+        {
+            m_componentManager.releaseActivationReadLock( "locate.service.ref" 
);
+        }
+    }
+
+
+    public Object[] locateServices( String name )
+    {
+        m_componentManager.obtainActivationReadLock( "locate.services" );
+        try
+        {
+            DependencyManager<S, ?> dm = 
m_componentManager.getDependencyManager( name );
+            return ( dm != null ) ? dm.getServices(this) : null;
+        }
+        finally
+        {
+            m_componentManager.releaseActivationReadLock( "locate.services" );
+        }
+    }
+
+
+    public BundleContext getBundleContext()
+    {
+        return m_componentManager.getBundleContext();
+    }
+
+
+    public Bundle getUsingBundle()
+    {
+        return m_usingBundle;
+    }
+
+
+    public ComponentInstance getComponentInstance()
+    {
+        return m_componentInstance;
+    }
+
+
+    public void enableComponent( String name )
+    {
+        BundleComponentActivator activator = m_componentManager.getActivator();
+        if ( activator != null )
+        {
+            activator.enableComponent( name );
+        }
+    }
+
+
+    public void disableComponent( String name )
+    {
+        BundleComponentActivator activator = m_componentManager.getActivator();
+        if ( activator != null )
+        {
+            activator.disableComponent( name );
+        }
+    }
+
+
+    public ServiceReference<S> getServiceReference()
+    {
+        return m_componentManager.getServiceReference();
+    }
+
+
+    //---------- Speculative MutableProperties interface 
------------------------------
+
+    public void setServiceProperties(Dictionary<String, ?> properties)
+    {
+        getComponentManager().setServiceProperties(properties );
+    }
+
+    //---------- ComponentInstance interface support 
------------------------------
+
+    S getImplementationObject( boolean requireAccessible )
+    {
+        if ( !requireAccessible || m_implementationAccessible )
+        {
+            return m_implementationObject;
+        }
+        try
+        {
+            if (accessibleLatch.await( m_componentManager.getLockTimeout(), 
TimeUnit.MILLISECONDS ) && m_implementationAccessible)
+            {
+                return m_implementationObject;
+            }
+        }
+        catch ( InterruptedException e )
+        {
+            try
+            {
+                if (accessibleLatch.await( 
m_componentManager.getLockTimeout(), TimeUnit.MILLISECONDS ) && 
m_implementationAccessible)
+                {
+                    return m_implementationObject;
+                }
+            }
+            catch ( InterruptedException e1 )
+            {
+                m_componentManager.log( LogService.LOG_INFO, "Interrupted 
twice waiting for implementation object to become accessible", e1 );
+            }
+            Thread.currentThread().interrupt();
+            return null;
+        }
+        return null;
+    }
+
+    private static class ComponentInstanceImpl<S> implements ComponentInstance
+    {
+        private final ComponentContextImpl<S> m_componentContext;
+
+        private ComponentInstanceImpl(ComponentContextImpl<S> 
m_componentContext)
+        {
+            this.m_componentContext = m_componentContext;
+        }
+
+
+        public Object getInstance()
+        {
+            return m_componentContext.getImplementationObject(true);
+        }
+
+
+        public void dispose()
+        {
+            m_componentContext.getComponentManager().dispose();
+        }
+
+    }
+}

Added: 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
URL: 
http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java?rev=1689973&view=auto
==============================================================================
--- 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
 (added)
+++ 
felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
 Wed Jul  8 22:10:14 2015
@@ -0,0 +1,416 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr.impl.manager;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.scr.component.ExtFactoryComponentInstance;
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.TargetedPID;
+import org.apache.felix.scr.impl.config.ComponentContainer;
+import org.apache.felix.scr.impl.helper.ComponentMethods;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.component.ComponentException;
+import org.osgi.service.component.ComponentFactory;
+import org.osgi.service.component.ComponentInstance;
+import org.osgi.service.log.LogService;
+
+/**
+ * The <code>ComponentFactoryImpl</code> extends the {@link 
AbstractComponentManager}
+ * class to implement the component factory functionality. As such the
+ * OSGi Declarative Services <code>ComponentFactory</code> interface is
+ * implemented.
+ * <p>
+ * In addition the {@link ComponentHolder} interface is implemented to use this
+ * class directly as the holder for component instances created by the
+ * {@link #newInstance(Dictionary)} method.
+ * <p>
+ * This class implements spec-compliant component factories and the felix 
+ * "persistent" component factory, where the factory is always registered 
whether or
+ * not all dependencies are present and the created components also persist 
whether or 
+ * not the dependencies are present to allow the component instance to exist.
+ */
+public class ComponentFactoryImpl<S> extends AbstractComponentManager<S> 
implements ComponentFactory, ComponentContainer<S>
+{
+
+    /**
+     * Contains the component instances created by calling the
+     * {@link #newInstance(Dictionary)} method. These component instances are
+     * provided with updated configuration (or deleted configuration) if
+     * such modifications for the component factory takes place.
+     * <p>
+     * The map is keyed by the component manager instances. The value of each
+     * entry is the same as the entry's key.
+     * This is an IdentityHashMap for speed, thus not a Set.
+     */
+    private final Map<SingleComponentManager<S>, SingleComponentManager<S>> 
m_componentInstances;
+
+    /**
+     * The configuration for the component factory. This configuration is
+     * supplied as the base configuration for each component instance created
+     * by the {@link #newInstance(Dictionary)} method.
+     */
+    private volatile Map<String, Object> m_configuration;
+    
+    /**
+     * Flag telling if our component factory is currently configured from 
config admin.
+     * We are configured when configuration policy is required and we have 
received the
+     * config admin properties, or when configuration policy is optional or 
ignored.
+     */
+    private volatile boolean m_hasConfiguration;
+    
+    /**
+     * Configuration change count (R5) or imitation (R4)
+     */
+    protected volatile long m_changeCount = -1;
+    
+    protected TargetedPID m_targetedPID;
+
+    public ComponentFactoryImpl( ComponentContainer<S> container )
+    {
+        super( container, new ComponentMethods() );
+        m_componentInstances = new IdentityHashMap<SingleComponentManager<S>, 
SingleComponentManager<S>>();
+        m_configuration = new HashMap<String, Object>();
+    }
+
+
+    protected boolean verifyDependencyManagers()
+    {
+        if (!getComponentMetadata().isPersistentFactoryComponent())
+        {
+            return super.verifyDependencyManagers();
+        }
+        return true;    
+    }
+    
+    @Override
+    public boolean isFactory()
+    {
+        return true;
+    }
+
+    /* (non-Javadoc)
+    * @see 
org.osgi.service.component.ComponentFactory#newInstance(java.util.Dictionary)
+    */
+    public ComponentInstance newInstance( Dictionary<String, ?> dictionary )
+    {
+        final SingleComponentManager<S> cm = createComponentManager();
+        log( LogService.LOG_DEBUG, "Creating new instance from component 
factory {0} with configuration {1}",
+                new Object[] {getComponentMetadata().getName(), dictionary}, 
null );
+
+        cm.setFactoryProperties( dictionary );
+        //configure the properties
+        cm.reconfigure( m_configuration, false );
+        // enable
+        cm.enableInternal();
+        //activate immediately
+        cm.activateInternal( getTrackingCount().get() );
+
+        ComponentInstance instance;
+        if ( getComponentMetadata().isPersistentFactoryComponent() ) 
+        {
+            instance = new ModifyComponentInstance<S>(cm);
+        }
+        else
+        {
+               instance = cm.getComponentInstance();
+               if ( instance == null ||  instance.getInstance() == null )
+               {
+                       // activation failed, clean up component manager
+                       cm.dispose( 
ComponentConstants.DEACTIVATION_REASON_DISPOSED );
+                       throw new ComponentException( "Failed activating 
component" );
+               }
+        }
+
+        synchronized ( m_componentInstances )
+        {
+            m_componentInstances.put( cm, cm );
+        }
+        
+        return instance;
+    }
+    
+    private static class ModifyComponentInstance<S> implements 
ExtFactoryComponentInstance
+    {
+        private final SingleComponentManager<S> cm;
+
+        public ModifyComponentInstance(SingleComponentManager<S> cm)
+        {
+            this.cm = cm;
+        }
+
+        public void dispose()
+        {
+            cm.dispose();            
+        }
+
+        public Object getInstance()
+        {
+            final ComponentInstance componentInstance = 
cm.getComponentInstance();
+            return componentInstance == null? null: 
componentInstance.getInstance();
+        }
+
+        public void modify(Dictionary<String, ?> properties)
+        {
+            cm.setFactoryProperties( properties );
+            cm.reconfigure(false);            
+        }
+        
+    }
+
+    /**
+     * Compares this {@code ComponentFactoryImpl} object to another object.
+     * 
+     * <p>
+     * A component factory impl is considered to be <b>equal to </b> another 
component
+     * factory impl if the component names are equal(using {@code 
String.equals}).
+     * 
+     * @param object The {@code ComponentFactoryImpl} object to be compared.
+     * @return {@code true} if {@code object} is a
+     *         {@code ComponentFactoryImpl} and is equal to this object;
+     *         {@code false} otherwise.
+     */
+    public boolean equals(Object object)
+    {
+        if (!(object instanceof ComponentFactoryImpl<?>))
+        {
+            return false;
+        }
+
+        ComponentFactoryImpl<?> other = (ComponentFactoryImpl<?>) object;
+        return 
getComponentMetadata().getName().equals(other.getComponentMetadata().getName());
+    }
+    
+   /**
+    * Returns a hash code value for the object.
+    * 
+    * @return An integer which is a hash code value for this object.
+    */
+   public int hashCode()
+   {
+       return getComponentMetadata().getName().hashCode();
+   }
+
+    /**
+     * The component factory does not have a component to delete.
+     * <p>
+     * But in the backwards compatible case any instances created for factory
+     * configuration instances are to disabled as a consequence of deactivating
+     * the component factory.
+     */
+    protected void deleteComponent( int reason )
+    {
+    }
+
+
+    @Override
+    protected String[] getProvidedServices()
+    {
+        return new String[] { ComponentFactory.class.getName() };
+    }
+
+
+    public boolean hasConfiguration()
+    {
+        return m_hasConfiguration;
+    }
+
+
+    /** 
+     * For ComponentFactoryImpl, this is used only for updating targets on the 
dependency managers, so we don't need any other 
+     * properties.
+     */
+    public Map<String, Object> getProperties()
+    {
+        Map<String, Object> props = new HashMap<String, Object>();
+
+        // add target properties of references
+        List<ReferenceMetadata> depMetaData = 
getComponentMetadata().getDependencies();
+        for ( ReferenceMetadata rm : depMetaData )
+        {
+            if ( rm.getTarget() != null )
+            {
+                props.put( rm.getTargetPropertyName(), rm.getTarget() );
+            }
+        }
+
+        // add target properties from configuration (if we have one)        
+        for ( String key :  m_configuration.keySet() )
+        {
+            if ( key.endsWith( ".target" ) )
+            {
+                props.put( key, m_configuration.get( key ) );
+            }
+        }
+
+        return props;
+    }
+    
+    public void setServiceProperties( Dictionary<String, ?> serviceProperties )
+    {
+        throw new IllegalStateException( "ComponentFactory service properties 
are immutable" );
+    }
+
+
+    public Dictionary<String, Object> getServiceProperties()
+    {
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+
+        // 112.5.5 The Component Factory service must register with the 
following properties
+        props.put( ComponentConstants.COMPONENT_NAME, 
getComponentMetadata().getName() );
+        props.put( ComponentConstants.COMPONENT_FACTORY, 
getComponentMetadata().getFactoryIdentifier() );
+
+        props.put( Constants.SERVICE_VENDOR, "The Apache Software Foundation" 
);
+
+        return props;
+    }
+
+    boolean hasInstance()
+    {
+        return false;
+    }
+
+    protected boolean collectDependencies(ComponentContextImpl<S> 
componentContext)
+    {
+        return true;
+    }
+
+    <T> void invokeUpdatedMethod( DependencyManager<S, T> dependencyManager, 
RefPair<S, T> ref, int trackingCount )
+    {
+    }
+
+    <T> void invokeBindMethod( DependencyManager<S, T> dependencyManager, 
RefPair<S, T> reference, int trackingCount )
+    {
+    }
+
+    <T> void invokeUnbindMethod( DependencyManager<S, T> dependencyManager, 
RefPair<S, T> oldRef, int trackingCount )
+    {
+    }
+
+    //---------- Component interface
+
+
+    public ComponentInstance getComponentInstance()
+    {
+        // a ComponentFactory is not a real component and as such does
+        // not have a ComponentInstance
+        return null;
+    }
+
+    /**
+     * Disposes off all components ever created by this component holder. This
+     * method is called if either the Declarative Services runtime is stopping
+     * or if the owning bundle is stopped. In both cases all components created
+     * by this holder must be disposed off.
+     */
+    public void dispose( int reason )
+    {
+        List<AbstractComponentManager<S>> cms = new 
ArrayList<AbstractComponentManager<S>>( );
+        getComponentManagers( m_componentInstances, cms );
+        for ( AbstractComponentManager<S> acm: cms )
+        {
+            acm.dispose( reason );
+        }
+
+        synchronized ( m_componentInstances )
+        {
+            m_componentInstances.clear();
+        }
+
+        // finally dispose the component factory itself
+        super.dispose( reason );
+    }
+
+
+    public void disposed( SingleComponentManager<S> component )
+    {
+        synchronized ( m_componentInstances )
+        {
+            m_componentInstances.remove( component );
+        }
+    }
+
+
+    //---------- internal
+
+
+    /**
+     * Creates an {@link SingleComponentManager} instance with the
+     * {@link BundleComponentActivator} and {@link ComponentMetadata} of this
+     * instance. The component manager is kept in the internal set of created
+     * components. The component is neither configured nor enabled.
+     */
+    private SingleComponentManager<S> createComponentManager()
+    {
+        return new SingleComponentManager<S>( this, getComponentMethods(), 
!getComponentMetadata().isPersistentFactoryComponent() );
+    }
+
+
+    protected void getComponentManagers( Map<?, SingleComponentManager<S>> 
componentMap, List<AbstractComponentManager<S>> componentManagers )
+    {
+        if ( componentMap != null )
+        {
+            synchronized ( componentMap )
+            {
+                componentManagers.addAll( componentMap.values() );
+            }
+        }
+    }
+
+    public TargetedPID getConfigurationTargetedPID(TargetedPID pid, 
TargetedPID factoryPid)
+    {
+        return m_targetedPID;
+    }
+
+
+       @Override
+       public void reconfigure(Map<String, Object> configuration, boolean 
configurationDeleted) {
+               m_configuration = configuration;
+               List<SingleComponentManager<S>> cms;
+               synchronized (m_componentInstances)
+        {
+            cms = new 
ArrayList<SingleComponentManager<S>>(m_componentInstances.keySet());
+        }
+               for (SingleComponentManager<S> cm: cms)
+               {
+                   cm.reconfigure( configuration, configurationDeleted);
+               }
+       }
+
+
+    @Override
+    public void getComponentManagers(List<AbstractComponentManager<S>> cms)
+    {
+        synchronized (m_componentInstances)
+        {
+            cms.addAll(m_componentInstances.keySet());
+        }
+    }
+
+
+}


Reply via email to