FELIX-3729 fix circular reference problems

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1424303 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java b/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
index 4672d87..168cfc2 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
@@ -673,6 +673,13 @@
                         dm.invokeBindMethodLate( serviceReference );
                     }
                 }
+
+                @Override
+                public String toString()
+                {
+                    return "Late binding task of reference " + serviceReference + " for dependencyManagers " + dependencyManagers;
+                }
+
             } );
         }
     }
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 bf323d6..1c50a1b 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
@@ -1860,9 +1860,20 @@
                 }
             }
         }
-        //TODO static and dynamic reluctant
+        //TODO dynamic reluctant
         RefPair<T> refPair = trackerRef.get().getService( ref );
-        m_bindMethods.getBind().getServiceObject( refPair, m_componentManager.getActivator().getBundleContext() );
+        synchronized ( refPair )
+        {
+            if (refPair.getServiceObject() != null)
+            {
+                m_componentManager.log( LogService.LOG_DEBUG,
+                        "DependencyManager : late binding of service reference {1} skipped as service has already been located",
+                        new Object[] {ref}, null );
+                //something else got the reference and may be binding it.
+                return;
+            }
+            m_bindMethods.getBind().getServiceObject( refPair, m_componentManager.getActivator().getBundleContext() );
+        }
         m_componentManager.invokeBindMethod( this, refPair );
     }
 
@@ -2310,7 +2321,10 @@
     {
         ServiceTracker<T, RefPair<T>> tracker = trackerRef.get();
         trackerRef.set( null ); //???
-        tracker.close();
+        if ( tracker != null )
+        {
+            tracker.close();
+        }
         registered = false;
         m_componentManager.log( LogService.LOG_DEBUG, "unregistering service listener for dependency {0}", new Object[]
                 {m_dependencyMetadata.getName()}, null );
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceTracker.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceTracker.java
index a71066f..136092f 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceTracker.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceTracker.java
@@ -1215,6 +1215,10 @@
                              */
                 }
                 object = tracked.get( item );
+                if (object == null) {
+                    //this can happen if a service is removed concurrently with tracker.close().
+                    return;
+                }
                 pendingRemovals++;
                 size = tracked.size() - pendingRemovals;
             }
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/CircularReferenceTest.java b/scr/src/test/java/org/apache/felix/scr/integration/CircularReferenceTest.java
index b548fc1..a44f911 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/CircularReferenceTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/CircularReferenceTest.java
@@ -252,11 +252,11 @@
         Object service = bundleContext.getService( serviceReference );
         assertNotNull( service );
 
-
+        delay();
         A a = ( A ) componentA.getComponentInstance().getInstance();
         assertEquals( 1, a.getBs().size() );
         B b = ( B ) componentB.getComponentInstance().getInstance();
-        assertEquals( 0, b.getAs().size() );
+        assertEquals( 1, b.getAs().size() );
     }
     /**
      * A > 1.1 > B > 0..1 > A Both should start, but B should not have an A reference.
@@ -287,10 +287,11 @@
         assertNotNull( serviceA );
 
 
+        delay();
         A a = ( A ) componentA.getComponentInstance().getInstance();
         assertEquals( 1, a.getBs().size() );
         B b = ( B ) componentB.getComponentInstance().getInstance();
-        assertEquals( 0, b.getAs().size() );
+        assertEquals( 1, b.getAs().size() );
 
 
         //disabling (removing the A service registration) and re-enabling will