FELIX-4004 Make DependencyManager.MultipleStaticCustomizer thread safe
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1462799 13f79535-47bb-0310-9956-ffa450edef68
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 9f6bf23..d8979f4 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,7 +24,9 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
+import java.util.HashSet;
import java.util.IdentityHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
@@ -544,7 +546,7 @@
private class MultipleStaticReluctantCustomizer extends AbstractCustomizer {
- private final Collection<RefPair<T>> refs = new ArrayList<RefPair<T>>();
+ private final AtomicReference<Collection<RefPair<T>>> refs = new AtomicReference<Collection<RefPair<T>>>();
private int trackingCount;
public RefPair<T> addingService( ServiceReference<T> serviceReference )
@@ -579,7 +581,8 @@
{
m_componentManager.log( LogService.LOG_DEBUG, "dm {0} tracking {1} MultipleStaticReluctant removed {2} (enter)", new Object[] {getName(), trackingCount, serviceReference}, null );
tracked( trackingCount );
- if ( isActive() )
+ Collection<RefPair<T>> refs = this.refs.get();
+ if ( isActive() && refs != null )
{
if (refs.contains( refPair ))
{
@@ -601,6 +604,19 @@
public boolean open()
{
boolean success = m_dependencyMetadata.isOptional();
+ Collection<RefPair<T>> refs = this.refs.get();
+ if (refs != null) {
+ //another thread is concurrently opening, and it got done already
+ for (RefPair<T> refPair: refs)
+ {
+ synchronized (refPair)
+ {
+ success |= m_bindMethods.getBind().getServiceObject( refPair, m_componentManager.getActivator().getBundleContext(), m_componentManager );
+ }
+ }
+ return success;
+ }
+ refs = new ArrayList<RefPair<T>>();
AtomicInteger trackingCount = new AtomicInteger( );
SortedMap<ServiceReference<T>, RefPair<T>> tracked = getTracker().getTracked( true, trackingCount );
for (RefPair<T> refPair: tracked.values())
@@ -611,25 +627,41 @@
}
refs.add(refPair) ;
}
- this.trackingCount = trackingCount.get();
+ if ( this.refs.compareAndSet( null, refs ) )
+ {
+ this.trackingCount = trackingCount.get();
+ }
+ else
+ {
+ //some other thread got done first. If we have more refPairs, we might need to unget some services.
+ Collection<RefPair<T>> actualRefs = this.refs.get();
+ refs.removeAll( actualRefs );
+ for (RefPair<T> ref: refs)
+ {
+ ungetService( ref );
+ }
+ }
return success;
}
public void close()
{
- AtomicInteger trackingCount = new AtomicInteger( );
- for ( RefPair<T> ref: getRefs( trackingCount ))
+ Collection<RefPair<T>> refs = this.refs.getAndSet( null );
+ if ( refs != null )
{
- ungetService( ref );
+ for ( RefPair<T> ref: refs )
+ {
+ ungetService( ref );
+ }
}
- refs.clear();
getTracker().deactivate();
}
public Collection<RefPair<T>> getRefs( AtomicInteger trackingCount )
{
trackingCount.set( this.trackingCount );
- return refs;
+ Collection<RefPair<T>> refs = this.refs.get();
+ return refs == null? Collections.<RefPair<T>>emptyList(): refs;
}
}