FELIX-3645 start of separating finding the bound services from creating the impl object.  Most itests fail. Some confusion about how bound services are recorded.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1381405 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
index 622ee32..da74b9b 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
@@ -103,6 +103,10 @@
         return m_methodName;
     }
 
+    protected final Method getMethod()
+    {
+        return m_method;
+    }
 
     protected final Class getComponentClass()
     {
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
index 4d22578..bcfeb18 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/BindMethod.java
@@ -21,9 +21,11 @@
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.Map;
 
 import org.apache.felix.scr.impl.Activator;
 import org.apache.felix.scr.impl.manager.AbstractComponentManager;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.log.LogService;
 import org.osgi.service.packageadmin.ExportedPackage;
@@ -40,6 +42,12 @@
 
     private final String m_referenceClassName;
 
+    private static final int SERVICE_REFERENCE = 1;
+    private static final int SERVICE_OBJECT = 2;
+    private static final int SERVICE_OBJECT_AND_MAP = 3;
+
+    private int m_paramStyle;
+
 
     public BindMethod( final AbstractComponentManager componentManager, final String methodName,
             final Class componentClass, final String referenceClassName )
@@ -95,6 +103,7 @@
                 {
                     getComponentManager().log( LogService.LOG_DEBUG, "doFindMethod: Found Method " + method, null );
                 }
+                m_paramStyle = SERVICE_REFERENCE;
                 return method;
             }
         }
@@ -122,6 +131,7 @@
                 method = getServiceObjectMethod( targetClass, parameterClass, acceptPrivate, acceptPackage );
                 if ( method != null )
                 {
+                    m_paramStyle = SERVICE_OBJECT;
                     return method;
                 }
             }
@@ -136,6 +146,7 @@
                 method = getServiceObjectAssignableMethod( targetClass, parameterClass, acceptPrivate, acceptPackage );
                 if ( method != null )
                 {
+                    m_paramStyle = SERVICE_OBJECT;
                     return method;
                 }
             }
@@ -154,6 +165,7 @@
                     method = getServiceObjectWithMapMethod( targetClass, parameterClass, acceptPrivate, acceptPackage );
                     if ( method != null )
                     {
+                        m_paramStyle = SERVICE_OBJECT_AND_MAP;
                         return method;
                     }
                 }
@@ -169,6 +181,7 @@
                         acceptPackage );
                     if ( method != null )
                     {
+                        m_paramStyle = SERVICE_OBJECT_AND_MAP;
                         return method;
                     }
                 }
@@ -541,34 +554,71 @@
         return null;
     }
 
+    public AbstractComponentManager.RefPair getServiceObject( ServiceReference ref, BundleContext context )
+    {
+        //??? this resolves which we need.... better way?
+        if ( methodExists() )
+        {
+            if (m_paramStyle == SERVICE_OBJECT || m_paramStyle == SERVICE_OBJECT_AND_MAP) {
+                Object service = context.getService( ref );
+                if ( service == null )
+                {
+                    getComponentManager().log(
+                         LogService.LOG_WARNING,
+                         "Could not get service from ref " + ref, null );
+                    return null;
+                }
+
+                return new AbstractComponentManager.RefPair(ref, service);
+            }
+        }
+        return new AbstractComponentManager.RefPair(ref, null);
+//        final Class[] paramTypes = getMethod( ).getParameterTypes();
+//        final Object[] params = new Object[paramTypes.length];
+//        boolean service = false;
+//        for ( int i = 0; i < params.length; i++ )
+//        {
+//            if ( paramTypes[i] == SERVICE_REFERENCE_CLASS )
+//            {
+//                params[i] = ref;
+//            }
+//            else if ( paramTypes[i] == MAP_CLASS )
+//            {
+//                params[i] = new ReadOnlyDictionary( ref );
+//            }
+//            else
+//            {
+//                params[i] = context.getService( ref );
+//                if ( params[i] == null )
+//                {
+//                    getComponentManager().log(
+//                        LogService.LOG_WARNING,
+//                        "Could not get service from ref " + ref, null );
+//                    return null;
+//                }
+//                service = true;
+//            }
+//        }
+//
+//        return new AbstractComponentManager.RefPair(params, service);
+    }
 
     protected Object[] getParameters( Method method, Object rawParameter )
     {
-        final Service service = ( Service ) rawParameter;
-        final Class[] paramTypes = method.getParameterTypes();
-        final Object[] params = new Object[paramTypes.length];
-        for ( int i = 0; i < params.length; i++ )
+        AbstractComponentManager.RefPair refPair = ( AbstractComponentManager.RefPair ) rawParameter; //{ServiceReference, Object}
+        if (m_paramStyle == SERVICE_REFERENCE )
         {
-            if ( paramTypes[i] == SERVICE_REFERENCE_CLASS )
-            {
-                params[i] = service.getReference();
-            }
-            else if ( paramTypes[i] == MAP_CLASS )
-            {
-                params[i] = new ReadOnlyDictionary( service.getReference() );
-            }
-            else
-            {
-                params[i] = service.getInstance();
-                if ( params[i] == null )
-                {
-                    throw new IllegalStateException( "Dependency Manager: Service " + service.getReference()
-                        + " has already gone, will not " + getMethodNamePrefix() );
-                }
-            }
+            return new Object[] {refPair.getRef()};
         }
-
-        return params;
+        if (m_paramStyle == SERVICE_OBJECT)
+        {
+            return new Object[] {refPair.getServiceObject()};
+        }
+        if (m_paramStyle == SERVICE_OBJECT_AND_MAP  )
+        {
+            return new Object[] {refPair.getServiceObject(), new ReadOnlyDictionary( refPair.getRef() )};
+        }
+        throw new IllegalStateException( "Unexpected m_paramStyle of " + m_paramStyle );
     }
 
 
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
index aecaddc..aeaaae9 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
@@ -27,9 +27,11 @@
 import java.util.Collections;
 import java.util.Dictionary;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -89,6 +91,9 @@
     // The dependency managers that manage every dependency
     private final List m_dependencyManagers;
 
+    //<Map<DependencyManager, Map<ServiceReference, Object[]>>>
+    private final AtomicReferenceWrapper m_dependencies_map;
+
     // A reference to the BundleComponentActivator
     private BundleComponentActivator m_activator;
 
@@ -121,11 +126,13 @@
         if (JUC_AVAILABLE)
         {
             m_stateLock = new JLock();
+            m_dependencies_map = new JAtomicReferenceWrapper();
             m_serviceRegistration = new JAtomicReferenceWrapper();
         }
         else
         {
             m_stateLock = new EDULock();
+            m_dependencies_map = new EDUAtomicReferenceWrapper();
             m_serviceRegistration = new EDUAtomicReferenceWrapper();
         }
 
@@ -580,9 +587,9 @@
         m_state.enable( this );
     }
 
-    final void activateInternal()
+    final boolean activateInternal()
     {
-        m_state.activate( this );
+        return m_state.activate( this );
     }
 
     final void deactivateInternal( int reason )
@@ -678,7 +685,7 @@
 
     protected void registerService( String[] provides )
     {
-        ServiceRegistration existing = m_serviceRegistration.get();
+        ServiceRegistration existing = ( ServiceRegistration ) m_serviceRegistration.get();
         if ( existing == null )
         {
             log( LogService.LOG_DEBUG, "registering services", null );
@@ -713,7 +720,7 @@
 
     final void unregisterComponentService()
     {
-        ServiceRegistration sr = m_serviceRegistration.get();
+        ServiceRegistration sr = ( ServiceRegistration ) m_serviceRegistration.get();
 
         if ( sr != null && m_serviceRegistration.compareAndSet( sr, null ) )
         {
@@ -722,6 +729,96 @@
         }
     }
 
+    protected final boolean collectDependencies()
+    {
+        Map old = ( Map ) m_dependencies_map.get();
+        if ( old != null)
+        {
+            return false;
+        }
+        Class implementationObjectClass = null;
+        try
+        {
+            implementationObjectClass = getActivator().getBundleContext().getBundle().loadClass(
+                    getComponentMetadata().getImplementationClassName() );
+        }
+        catch ( ClassNotFoundException e )
+        {
+            log( LogService.LOG_ERROR, "Could not load implementation object class", e );
+            return false;
+        }
+        Map newDeps = new HashMap( );//<DependencyManager, Map<ServiceReference, RefPair>
+        for (Iterator it = m_dependencyManagers.iterator(); it.hasNext(); )
+        {
+            DependencyManager dependencyManager = ( DependencyManager ) it.next();
+
+            dependencyManager.initBindingMethods( implementationObjectClass );
+            if (!dependencyManager.prebind( newDeps) )
+            {
+                //not actually satisfied any longer
+                returnServices( newDeps );
+                return false;
+            }
+        }
+        if ( !m_dependencies_map.compareAndSet( old, newDeps ))
+        {
+            returnServices(newDeps);
+            return false;
+        }
+        return true;
+    }
+
+    private void returnServices( Map deps )
+    {
+         for (Iterator it = deps.values().iterator(); it.hasNext(); )
+         {
+             Map refs = ( Map ) it.next();
+             if ( refs != null )
+             {
+                 for (Iterator ri = refs.entrySet().iterator(); ri.hasNext(); )
+                 {
+                     Map.Entry entry = ( Map.Entry ) ri.next();
+                     RefPair args = ( RefPair ) entry.getValue();
+                     if ( args.getServiceObject() != null )
+                     {
+                         getActivator().getBundleContext().ungetService( (ServiceReference) entry.getKey() );
+                     }
+                 }
+             }
+         }
+    }
+
+    public static class RefPair
+    {
+        private final ServiceReference ref;
+        private Object serviceObject;
+
+        public RefPair( ServiceReference ref, Object serviceObject )
+        {
+            this.ref = ref;
+            this.serviceObject = serviceObject;
+        }
+
+        public ServiceReference getRef()
+        {
+            return ref;
+        }
+
+        public Object getServiceObject()
+        {
+            return serviceObject;
+        }
+
+        public void setServiceObject( Object serviceObject )
+        {
+            this.serviceObject = serviceObject;
+        }
+    }
+
+    Map getDependencyMap()
+    {
+        return ( Map ) m_dependencies_map.get();
+    }
 
     //**********************************************************************************************************
     public BundleComponentActivator getActivator()
@@ -739,7 +836,7 @@
 
     final ServiceRegistration getServiceRegistration()
     {
-        return m_serviceRegistration.get();
+        return ( ServiceRegistration ) m_serviceRegistration.get();
     }
 
 
@@ -755,6 +852,12 @@
         m_dependencyManagers.clear();
     }
 
+    //<DepeendencyManager, Map<ServiceReference, Object[]>>
+    protected Map getParameterMap()
+    {
+        return ( Map ) m_dependencies_map.get();
+    }
+
 
     /**
      * Returns <code>true</code> if logging for the given level is enabled.
@@ -1151,9 +1254,10 @@
         }
 
 
-        void activate( AbstractComponentManager acm )
+        boolean activate( AbstractComponentManager acm )
         {
             log( acm, "activate" );
+            return false;
 //            throw new IllegalStateException("activate" + this);
         }
 
@@ -1291,14 +1395,19 @@
             return m_inst;
         }
 
-
-        void activate( AbstractComponentManager acm )
+        /**
+         * returns true if this thread succeeds in activating the component, or the component is not able to be activated.
+         * Returns false if some other thread succeeds in activating the component.
+         * @param acm
+         * @return
+         */
+        boolean activate( AbstractComponentManager acm )
         {
             if ( !acm.isActivatorActive() )
             {
                 acm.log( LogService.LOG_DEBUG, "Bundle's component activator is not active; not activating component",
                     null );
-                return;
+                return true;
             }
 
             acm.log( LogService.LOG_DEBUG, "Activating component", null );
@@ -1308,15 +1417,7 @@
             if ( !acm.hasConfiguration() && acm.getComponentMetadata().isConfigurationRequired() )
             {
                 acm.log( LogService.LOG_DEBUG, "Missing required configuration, cannot activate", null );
-                return;
-            }
-
-            // Before creating the implementation object, we are going to
-            // test if all the mandatory dependencies are satisfied
-            if ( !acm.verifyDependencyManagers( acm.getProperties() ) )
-            {
-                acm.log( LogService.LOG_DEBUG, "Not all dependencies satisfied, cannot activate", null );
-                return;
+                return true;
             }
 
             // Before creating the implementation object, we are going to
@@ -1325,7 +1426,15 @@
             {
                 acm.log( LogService.LOG_DEBUG, "Component is not permitted to register all services, cannot activate",
                     null );
-                return;
+                return true;
+            }
+
+            // Before creating the implementation object, we are going to
+            // test if all the mandatory dependencies are satisfied
+            if ( !acm.verifyDependencyManagers( acm.getProperties() ) )
+            {
+                acm.log( LogService.LOG_DEBUG, "Not all dependencies satisfied, cannot activate", null );
+                return true;
             }
 
             // set satisfied state before registering the service because
@@ -1348,6 +1457,10 @@
             // 4. Call the activate method, if present
             if ( ( acm.isImmediate() || acm.getComponentMetadata().isFactory() ) )
             {
+                 if ( !acm.collectDependencies() )
+                 {
+                     return false;
+                 }
                 acm.escalateLock( "AbstractComponentManager.Unsatisifed.activate.1" );
                 try
                 {
@@ -1365,6 +1478,7 @@
                 }
 
             }
+            return true;
 
         }
 
@@ -1605,7 +1719,7 @@
             return m_inst;
         }
 
-        void activate( AbstractComponentManager acm )
+        boolean activate( AbstractComponentManager acm )
         {
             throw new IllegalStateException( "activate: " + this );
         }
@@ -1735,9 +1849,9 @@
 
     private interface AtomicReferenceWrapper
     {
-        ServiceRegistration get();
+        Object get();
 
-        boolean compareAndSet(ServiceRegistration expected, ServiceRegistration replacement);
+        boolean compareAndSet(Object expected, Object replacement);
 
     }
 
@@ -1745,12 +1859,12 @@
     {
         private final AtomicReference ref = new AtomicReference(  );
 
-        public ServiceRegistration get()
+        public Object get()
         {
-            return ( ServiceRegistration ) ref.get();
+            return ref.get();
         }
 
-        public boolean compareAndSet(ServiceRegistration expected, ServiceRegistration replacement)
+        public boolean compareAndSet(Object expected, Object replacement)
         {
             return ref.compareAndSet( expected, replacement );
         }
@@ -1760,12 +1874,12 @@
     {
         private final EDU.oswego.cs.dl.util.concurrent.SynchronizedRef ref = new EDU.oswego.cs.dl.util.concurrent.SynchronizedRef( null );
 
-        public ServiceRegistration get()
+        public Object get()
         {
-            return ( ServiceRegistration ) ref.get();
+            return ref.get();
         }
 
-        public boolean compareAndSet(ServiceRegistration expected, ServiceRegistration replacement)
+        public boolean compareAndSet(Object expected, Object replacement)
         {
             return ref.commit( expected, replacement );
         }
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
index 3943fbe..3805221 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
@@ -24,6 +24,7 @@
 import java.util.Collections;
 import java.util.Dictionary;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -55,11 +56,11 @@
 public class DependencyManager implements ServiceListener, Reference
 {
     // mask of states ok to send events
-    private static final int STATE_MASK = Component.STATE_UNSATISFIED
-        | Component.STATE_ACTIVE | Component.STATE_REGISTERED | Component.STATE_FACTORY;
+    private static final int STATE_MASK = //Component.STATE_UNSATISFIED |
+         Component.STATE_ACTIVE | Component.STATE_REGISTERED | Component.STATE_FACTORY;
 
     // pseudo service to mark a bound service without actual service instance
-    private static final Object BOUND_SERVICE_SENTINEL = new Object();
+//    private static final Object BOUND_SERVICE_SENTINEL = new Object();
 
     // the component to which this dependency belongs
     private final AbstractComponentManager m_componentManager;
@@ -68,7 +69,7 @@
     private final ReferenceMetadata m_dependencyMetadata;
 
     // The map of bound services indexed by their ServiceReference
-    private final Map m_bound;
+//    private final Map m_bound;
 
     // the number of matching services registered in the system
     private volatile int m_size;
@@ -101,7 +102,7 @@
     {
         m_componentManager = componentManager;
         m_dependencyMetadata = dependency;
-        m_bound = Collections.synchronizedMap( new HashMap() );
+//        m_bound = Collections.synchronizedMap( new HashMap() );
 
 
         // dump the reference information if DEBUG is enabled
@@ -120,8 +121,12 @@
     /**
      * Initialize binding methods.
      */
-    private void initBindingMethods(Class instanceClass)
+    void initBindingMethods(Class instanceClass)
     {
+        if (m_bind != null)
+        {
+            return;
+        }
         m_bind = new BindMethod( m_componentManager,
                                  m_dependencyMetadata.getBind(),
                                  instanceClass,
@@ -290,14 +295,34 @@
                     { m_dependencyMetadata.getName() }, null );
 
             // immediately try to activate the component (FELIX-2368)
-            m_componentManager.activateInternal();
+            boolean handled = m_componentManager.activateInternal();
+            if (!handled)
+            {
+                Map dependenciesMap = m_componentManager.getDependencyMap();
+                if (dependenciesMap  != null) {
+                    //someone else has managed to activate
+                    Map references = ( Map ) dependenciesMap.get( this );
+                    if (references == null )
+                    {
+                        throw new IllegalStateException( "Allegedly active but dependency manager not represented: " + this );
+                    }
+                    handled = references.containsKey( reference );
+                }
+            }
+            if (handled)
+            {
+                return;
+            }
+            //release our read lock and wait for activation to complete
+            m_componentManager.escalateLock( "DependencyManager.serviceAdded.nothandled.1" );
+            m_componentManager.deescalateLock( "DependencyManager.serviceAdded.nothandled.2" );
         }
 
         // otherwise check whether the component is in a state to handle the event
-        else if ( handleServiceEvent() )
+        if ( handleServiceEvent() )
         {
 
-            // FELIX-1413: if the dependency is static and the component is
+            // FELIX-1413: if the dependency is static and reluctant and the component is
             // satisfied (active) added services are not considered until
             // the component is reactivated for other reasons.
             if ( m_dependencyMetadata.isStatic() )
@@ -308,12 +333,16 @@
                             "Dependency Manager: Added service {0} is ignored for static reluctant reference", new Object[]
                             {m_dependencyMetadata.getName()}, null );
                 }
-                else if ( m_dependencyMetadata.isMultiple() ||
-                        m_bound.isEmpty() ||
-                        reference.compareTo( m_bound.keySet().iterator().next() ) > 0 )
+                else
                 {
-                    m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
-                    m_componentManager.activateInternal();
+                    Map bound = ( Map ) m_componentManager.getDependencyMap().get( this );
+                    if ( m_dependencyMetadata.isMultiple() ||
+                                            bound.isEmpty() ||
+                                            reference.compareTo( bound.keySet().iterator().next() ) > 0 )
+                                    {
+                                        m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
+                                        m_componentManager.activateInternal();
+                                    }
                 }
             }
 
@@ -330,7 +359,8 @@
                 else if ( !isReluctant() )
                 {
                     //dynamic greedy single: bind then unbind
-                    ServiceReference oldRef = ( ServiceReference ) m_bound.keySet().iterator().next();
+                    Map bound = ( Map ) m_componentManager.getDependencyMap().get( this );
+                    ServiceReference oldRef = ( ServiceReference ) bound.keySet().iterator().next();
                     if ( reference.compareTo( oldRef ) > 0 )
                     {
                         invokeBindMethod( reference );
@@ -387,7 +417,7 @@
         // otherwise check whether the component is in a state to handle the event
         else if ( handleServiceEvent() )
         {
-            // if the dependency is static, we have to reactivate the component
+            // if the dependency is static, we have to deactivate the component
             // to "remove" the dependency
             if ( m_dependencyMetadata.isStatic() )
             {
@@ -416,7 +446,10 @@
                 {
                     // if the dependency is mandatory and no replacement is
                     // available, bind returns false and we deactivate
-                    if ( !bind() )
+                    // bind best matching service
+                    ServiceReference ref = getFrameworkServiceReference();
+
+                    if ( ref == null )
                     {
                         m_componentManager
                             .log(
@@ -426,6 +459,10 @@
                                     { m_dependencyMetadata.getName(), m_dependencyMetadata.getInterface() }, null );
                         m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
                     }
+                    else
+                    {
+                        invokeBindMethod( ref );
+                    }
                 }
 
                 // call the unbind method if one is defined
@@ -741,12 +778,14 @@
      */
     private ServiceReference[] getBoundServiceReferences()
     {
-        if ( m_bound.isEmpty() )
+        Map dependencyMap = m_componentManager.getDependencyMap();
+        Map bound = ( Map ) dependencyMap.get( this );
+        if ( bound.isEmpty() )
         {
             return null;
         }
 
-        return ( ServiceReference[] ) m_bound.keySet().toArray( new ServiceReference[m_bound.size()] );
+        return ( ServiceReference[] ) bound.keySet().toArray( new ServiceReference[bound.size()] );
     }
 
 
@@ -755,7 +794,8 @@
      */
     private boolean isBound()
     {
-        return !m_bound.isEmpty();
+        Map bound = ( Map ) m_componentManager.getDependencyMap().get( this );
+        return !bound.isEmpty();
     }
 
 
@@ -773,26 +813,26 @@
      * @param serviceReference The reference to the service being marked as
      *      bound.
      */
-    private void bindService( ServiceReference serviceReference )
-    {
-        m_bound.put( serviceReference, BOUND_SERVICE_SENTINEL );
-    }
+//    private void bindService( ServiceReference serviceReference )
+//    {
+//        m_bound.put( serviceReference, BOUND_SERVICE_SENTINEL );
+//    }
 
 
     /**
-     * Returns the bound service represented by the given service reference
+     * Returns the RefPair containing the given service reference and the bound service
      * or <code>null</code> if this is instance is not currently bound to that
      * service.
      *
      * @param serviceReference The reference to the bound service
      *
-     * @return the service for the reference or the {@link #BOUND_SERVICE_SENTINEL}
+     * @return RefPair the reference and service for the reference
      *      if the service is bound or <code>null</code> if the service is not
      *      bound.
      */
-    private Object getBoundService( ServiceReference serviceReference )
+    private AbstractComponentManager.RefPair getBoundService( ServiceReference serviceReference )
     {
-        return m_bound.get( serviceReference );
+        return ( AbstractComponentManager.RefPair ) (( Map ) m_componentManager.getDependencyMap().get( this )).get(serviceReference);
     }
 
 
@@ -810,16 +850,16 @@
     Object getService( ServiceReference serviceReference )
     {
         // check whether we already have the service and return that one
-        Object service = getBoundService( serviceReference );
-        if ( service != null && service != BOUND_SERVICE_SENTINEL )
+        AbstractComponentManager.RefPair refPair = getBoundService( serviceReference );
+        if ( refPair != null && refPair.getServiceObject() != null )
         {
-            return service;
+            return refPair.getServiceObject();
         }
-
+        Object serviceObject = null;
         // otherwise acquire the service
         try
         {
-            service = m_componentManager.getActivator().getBundleContext().getService( serviceReference );
+            serviceObject = m_componentManager.getActivator().getBundleContext().getService( serviceReference );
         }
         catch ( Exception e )
         {
@@ -829,17 +869,25 @@
             m_componentManager.log( LogService.LOG_ERROR, "Failed getting service {0} ({1}/{2,number,#})", new Object[]
                 { m_dependencyMetadata.getName(), m_dependencyMetadata.getInterface(),
                     serviceReference.getProperty( Constants.SERVICE_ID ) }, e );
-            service = null;
+            return null;
         }
 
         // keep the service for latter ungetting
-        if ( service != null )
+        if ( serviceObject != null )
         {
-            m_bound.put( serviceReference, service );
+            if (refPair != null)
+            {
+                refPair.setServiceObject( serviceObject );
+            }
+            else
+            {
+                refPair = new AbstractComponentManager.RefPair( serviceReference,  serviceObject );
+                ((Map)m_componentManager.getDependencyMap().get( this )) .put( serviceReference, refPair );
+            }
         }
 
         // return the acquired service (may be null of course)
-        return service;
+        return serviceObject;
     }
 
 
@@ -850,8 +898,8 @@
     void ungetService( ServiceReference serviceReference )
     {
         // check we really have this service, do nothing if not
-        Object service = m_bound.remove( serviceReference );
-        if ( service != null && service != BOUND_SERVICE_SENTINEL )
+        AbstractComponentManager.RefPair refPair  = ( AbstractComponentManager.RefPair ) ((Map )m_componentManager.getDependencyMap().get( this )).remove( serviceReference );
+        if ( refPair != null && refPair.getServiceObject() != null )
         {
             BundleComponentActivator activator = m_componentManager.getActivator();
             if ( activator != null )
@@ -917,11 +965,11 @@
     }
 
 
-    boolean open( Object instance )
+    boolean open( Object instance, Map parameters )
     {
-        initBindingMethods( instance.getClass() );
+//        initBindingMethods( instance.getClass() );
         m_componentInstance = instance;
-        return bind();
+        return bind(parameters);
     }
 
 
@@ -938,13 +986,77 @@
         finally
         {
             m_componentInstance = null;
-            m_bind = null;
-            m_unbind = null;
-            m_bound.clear();
-
+//            m_bind = null;
+//            m_unbind = null;
+//            m_updated = null;
         }
     }
 
+    //returns Map<ServiceReference, Object[]>
+    boolean prebind( Map dependencyMap)
+    {
+        // If no references were received, we have to check if the dependency
+        // is optional, if it is not then the dependency is invalid
+        if ( !isSatisfied() )
+        {
+            return false;
+        }
+
+        // if no bind method is configured or if this is a delayed component,
+        // we have nothing to do and just signal success
+        if ( m_dependencyMetadata.getBind() == null )
+        {
+            dependencyMap.put( this, new HashMap( ) );
+            return true;
+        }
+
+        Map result = new HashMap(); //<ServiceReference, Object[]>
+        // assume success to begin with: if the dependency is optional,
+        // we don't care, whether we can bind a service. Otherwise, we
+        // require at least one service to be bound, thus we require
+        // flag being set in the loop below
+        boolean success = m_dependencyMetadata.isOptional();
+
+        // Get service reference(s)
+        if ( m_dependencyMetadata.isMultiple() )
+        {
+            // bind all registered services
+            ServiceReference[] refs = getFrameworkServiceReferences();
+            if ( refs != null )
+            {
+                for ( int index = 0; index < refs.length; index++ )
+                {
+                    AbstractComponentManager.RefPair refPair = m_bind.getServiceObject( refs[index], m_componentManager.getActivator().getBundleContext() );
+                    // success is if we have the minimal required number of services bound
+                    if ( refPair != null )
+                    {
+                        result.put( refs[index], refPair );
+                        // of course, we have success if the service is bound
+                        success = true;
+                    }
+                }
+            }
+        }
+        else
+        {
+            // bind best matching service
+            ServiceReference ref = getFrameworkServiceReference();
+            AbstractComponentManager.RefPair refPair = m_bind.getServiceObject( ref, m_componentManager.getActivator().getBundleContext() );
+            // success is if we have the minimal required number of services bound
+            if ( refPair != null )
+            {
+                result.put( ref, refPair );
+                // of course, we have success if the service is bound
+                success = true;
+            }
+        }
+
+        // success will be true, if the service is optional or if at least
+        // one service was available to be bound (regardless of whether the
+        // bind method succeeded or not)
+        dependencyMap.put( this, result );
+        return success;
+    }
 
     /**
      * initializes a dependency. This method binds all of the service
@@ -953,7 +1065,7 @@
      * @return true if the dependency is satisfied and at least the minimum
      *      number of services could be bound. Otherwise false is returned.
      */
-    private boolean bind()
+    private boolean bind( Map parameters )
     {
         // If no references were received, we have to check if the dependency
         // is optional, if it is not then the dependency is invalid
@@ -975,38 +1087,12 @@
         // flag being set in the loop below
         boolean success = m_dependencyMetadata.isOptional();
 
-        // Get service reference(s)
-        if ( m_dependencyMetadata.isMultiple() )
+        for ( Iterator i = parameters.entrySet().iterator(); i.hasNext(); )
         {
-            // bind all registered services
-            ServiceReference[] refs = getFrameworkServiceReferences();
-            if ( refs != null )
-            {
-                for ( int index = 0; index < refs.length; index++ )
-                {
-                    // success is if we have the minimal required number of services bound
-                    if ( invokeBindMethod( refs[index] ) )
-                    {
-                        // of course, we have success if the service is bound
-                        success = true;
-                    }
-                }
-            }
+            Map.Entry entry = ( Map.Entry ) i.next();
+            invokeBindMethod( ( AbstractComponentManager.RefPair ) entry.getValue());
+            success = true;
         }
-        else
-        {
-            // bind best matching service
-            ServiceReference ref = getFrameworkServiceReference();
-            if ( ref != null && invokeBindMethod( ref ) )
-            {
-                // of course, we have success if the service is bound
-                success = true;
-            }
-        }
-
-        // success will be true, if the service is optional or if at least
-        // one service was available to be bound (regardless of whether the
-        // bind method succeeded or not)
         return success;
     }
 
@@ -1058,6 +1144,20 @@
         }
     }
 
+    private boolean invokeBindMethod( ServiceReference ref )
+    {
+        //event driven, and we already checked this ref is not yet handled.
+        Map dependencyMap = m_componentManager.getDependencyMap();
+        if ( dependencyMap != null )
+        {
+            Map deps = ( Map ) dependencyMap.get( this );
+            BundleContext bundleContext = m_componentManager.getActivator().getBundleContext();
+            AbstractComponentManager.RefPair refPair = m_bind.getServiceObject( ref, bundleContext );
+            deps.put( ref, refPair );
+            return invokeBindMethod( refPair );
+        }
+        return false;
+    }
 
     /**
      * Calls the bind method. In case there is an exception while calling the
@@ -1067,15 +1167,15 @@
      * If the reference is singular and a service has already been bound to the
      * component this method has no effect and just returns <code>true</code>.
      *
-     * @param ref A ServiceReference with the service that will be bound to the
-     *            instance object
+     * @param refPair the service reference, service object tuple.
+     *
      * @return true if the service should be considered bound. If no bind
      *      method is found or the method call fails, <code>true</code> is
      *      returned. <code>false</code> is only returned if the service must
      *      be handed over to the bind method but the service cannot be
      *      retrieved using the service reference.
      */
-    private boolean invokeBindMethod( final ServiceReference ref )
+    private boolean invokeBindMethod( AbstractComponentManager.RefPair refPair )
     {
         // The bind method is only invoked if the implementation object is not
         // null. This is valid for both immediate and delayed components
@@ -1083,20 +1183,7 @@
         {
             if ( m_bind != null )
             {
-                MethodResult result = m_bind.invoke( m_componentInstance, new BindMethod.Service()
-                {
-                    public ServiceReference getReference()
-                    {
-                        bindService( ref );
-                        return ref;
-                    }
-
-
-                    public Object getInstance()
-                    {
-                        return getService( ref );
-                    }
-                }, MethodResult.VOID );
+                MethodResult result = m_bind.invoke( m_componentInstance, refPair, MethodResult.VOID );
                 if ( result == null )
                 {
                     return false;
@@ -1135,19 +1222,8 @@
         // null. This is valid for both immediate and delayed components
         if ( m_componentInstance != null )
         {
-            MethodResult methodResult = m_updated.invoke( m_componentInstance, new BindMethod.Service()
-            {
-                public ServiceReference getReference()
-                {
-                    return ref;
-                }
-
-
-                public Object getInstance()
-                {
-                    return getService( ref );
-                }
-            }, MethodResult.VOID );
+            Object serviceObject = ((Map)m_componentManager.getDependencyMap().get( this )).get( ref );
+            MethodResult methodResult = m_updated.invoke( m_componentInstance, new Object[] {ref, serviceObject}, MethodResult.VOID );
             if ( methodResult != null)
             {
                 m_componentManager.setServiceProperties( methodResult );
@@ -1155,7 +1231,7 @@
         }
         else
         {
-            // don't care whether we can or cannot call the unbind method
+            // don't care whether we can or cannot call the updated method
             // if the component instance has already been cleared by the
             // close() method
             m_componentManager.log( LogService.LOG_DEBUG,
@@ -1180,19 +1256,8 @@
         // null. This is valid for both immediate and delayed components
         if ( m_componentInstance != null )
         {
-            MethodResult methodResult = m_unbind.invoke( m_componentInstance, new BindMethod.Service()
-            {
-                public ServiceReference getReference()
-                {
-                    return ref;
-                }
-
-
-                public Object getInstance()
-                {
-                    return getService( ref );
-                }
-            }, MethodResult.VOID );
+            AbstractComponentManager.RefPair refPair = ( AbstractComponentManager.RefPair ) ((Map )m_componentManager.getDependencyMap().get( this )).get( ref );
+            MethodResult methodResult = m_unbind.invoke( m_componentInstance, refPair, MethodResult.VOID );
             if ( methodResult != null )
             {
                 m_componentManager.setServiceProperties( methodResult );
@@ -1334,6 +1399,12 @@
             m_targetFilter = null;
         }
 
+        if ( m_componentManager.getDependencyMap() == null)
+        {
+            //component is inactive, no bindings to change.
+            return;
+        }
+        //component is active, we need to check what might have changed.
         // check for services to be removed
         if ( m_targetFilter != null )
         {
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
index 6989119..5f0d8e0 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ImmediateComponentManager.java
@@ -23,6 +23,7 @@
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.felix.scr.impl.BundleComponentActivator;
 import org.apache.felix.scr.impl.config.ComponentHolder;
@@ -204,6 +205,7 @@
         }
 
         // 3. Bind the target services
+        Map parameters = getParameterMap();
         Iterator it = getDependencyManagers();
         while ( it.hasNext() )
         {
@@ -211,7 +213,8 @@
             // creating the instance fails here, so we deactivate and return
             // null.
             DependencyManager dm = ( DependencyManager ) it.next();
-            if ( !dm.open( implementationObject ) )
+            Map params = ( Map ) parameters.get( dm );  //<ServiceReference, RefPair>
+            if ( !dm.open( implementationObject, params ) )
             {
                 log( LogService.LOG_ERROR, "Cannot create component instance due to failure to bind reference {0}",
                         new Object[]
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java b/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
index 595f61c..aec7ea4 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
@@ -21,6 +21,7 @@
 
 import junit.framework.TestCase;
 
+import org.apache.felix.scr.impl.manager.AbstractComponentManager;
 import org.apache.felix.scr.impl.manager.ImmediateComponentManager;
 import org.apache.felix.scr.impl.manager.components.FakeService;
 import org.apache.felix.scr.impl.manager.components.T1;
@@ -29,6 +30,7 @@
 import org.apache.felix.scr.impl.manager.components2.T2;
 import org.apache.felix.scr.impl.metadata.ComponentMetadata;
 import org.easymock.EasyMock;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 
@@ -38,32 +40,24 @@
 
     private ServiceReference m_serviceReference;
     private FakeService m_serviceInstance;
-    private BindMethod.Service m_service;
+    private BundleContext m_context;
 
 
     public void setUp()
     {
         m_serviceReference = (ServiceReference) EasyMock.createNiceMock( ServiceReference.class );
         m_serviceInstance = (FakeService) EasyMock.createNiceMock( FakeService.class );
-        m_service = new BindMethod.Service()
-        {
-            public ServiceReference getReference()
-            {
-                return m_serviceReference;
-            }
+        m_context = ( BundleContext ) EasyMock.createNiceMock( BundleContext.class );
 
+        EasyMock.expect( m_context.getService( m_serviceReference ) ).andReturn( m_serviceInstance )
+                .anyTimes();
 
-            public Object getInstance()
-            {
-                return m_serviceInstance;
-            }
-        };
         EasyMock.expect( m_serviceReference.getPropertyKeys() ).andReturn( new String[]
             { Constants.SERVICE_ID } ).anyTimes();
         EasyMock.expect( m_serviceReference.getProperty( Constants.SERVICE_ID ) ).andReturn( "Fake Service" )
             .anyTimes();
         EasyMock.replay( new Object[]
-            { m_serviceReference } );
+            { m_serviceReference, m_context } );
     }
 
 
@@ -441,7 +435,8 @@
         ImmediateComponentManager icm = new ImmediateComponentManager( null, null, metadata );
         BindMethod bm = new BindMethod( icm, methodName, component.getClass(),
                 FakeService.class.getName() );
-        bm.invoke( component, m_service, null );
+        AbstractComponentManager.RefPair refPair = bm.getServiceObject( m_serviceReference, m_context );
+        bm.invoke( component, refPair, null );
         assertEquals( expectCallPerformed, component.callPerformed );
     }
 }