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