FELIX-3729 fix various bugs
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1424302 13f79535-47bb-0310-9956-ffa450edef68
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 86a8a1f..2c0f91b 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
@@ -563,6 +563,7 @@
Object service = context.getService( refPair.getRef() );
if ( service == null )
{
+ refPair.setFailed();
getLogger().log(
LogService.LOG_WARNING,
"Could not get service from ref " + refPair.getRef(), null );
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 3d5c070..bf323d6 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
@@ -26,6 +26,7 @@
import java.util.Dictionary;
import java.util.List;
import java.util.SortedMap;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.felix.scr.Component;
@@ -185,6 +186,10 @@
{
}
+ public void removingService( ServiceReference<T> item, RefPair<T> object, int size )
+ {
+ }
+
public void removedService( ServiceReference<T> serviceReference, RefPair<T> refPair )
{
if ( !isOptional() )
@@ -221,7 +226,10 @@
RefPair<T> refPair = new RefPair<T>( serviceReference );
if (isActive())
{
- m_bindMethods.getBind().getServiceObject( refPair, m_componentManager.getActivator().getBundleContext());
+ if (!m_bindMethods.getBind().getServiceObject( refPair, m_componentManager.getActivator().getBundleContext()))
+ {
+ m_componentManager.getActivator().registerMissingDependency( DependencyManager.this, serviceReference );
+ }
}
return refPair;
}
@@ -230,7 +238,10 @@
{
if (isActive())
{
- m_componentManager.invokeBindMethod( DependencyManager.this, refPair );
+ if ( !refPair.isFailed() )
+ {
+ m_componentManager.invokeBindMethod( DependencyManager.this, refPair );
+ }
}
else if ( isTrackerOpened() && !isOptional() )
{
@@ -246,18 +257,11 @@
}
}
- public void removedService( ServiceReference<T> serviceReference, RefPair<T> refPair )
+ public void removingService( ServiceReference<T> item, RefPair<T> refPair, int size )
{
if ( isActive() )
{
- boolean unbind = true;
- if ( !isOptional() )
- {
- if (getTracker().isEmpty())
- {
- unbind = false;
- }
- }
+ boolean unbind = isOptional() || size > 0;
if ( unbind )
{
m_componentManager.invokeUnbindMethod( DependencyManager.this, refPair );
@@ -267,6 +271,10 @@
m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE, false );
}
}
+ }
+
+ public void removedService( ServiceReference<T> serviceReference, RefPair<T> refPair )
+ {
if (refPair.getServiceObject() != null)
{
m_componentManager.getActivator().getBundleContext().ungetService( serviceReference );
@@ -281,7 +289,14 @@
{
synchronized (refPair)
{
- success |= m_bindMethods.getBind().getServiceObject( refPair, m_componentManager.getActivator().getBundleContext());
+ if (m_bindMethods.getBind().getServiceObject( refPair, m_componentManager.getActivator().getBundleContext()))
+ {
+ success = true;
+ }
+ else
+ {
+ m_componentManager.getActivator().registerMissingDependency( DependencyManager.this, refPair.getRef() );
+ }
}
}
return success;
@@ -309,6 +324,9 @@
private class MultipleStaticGreedyCustomizer extends AbstractCustomizer {
+ private final AtomicInteger reactivateCount = new AtomicInteger( );
+
+
public RefPair<T> addingService( ServiceReference<T> serviceReference )
{
RefPair<T> refPair = new RefPair<T>( serviceReference );
@@ -344,16 +362,31 @@
}
}
- public void removedService( ServiceReference<T> serviceReference, RefPair<T> refPair )
+ public void removingService( ServiceReference<T> item, RefPair<T> object, int size )
{
if ( isActive() )
{
+ //deactivate while ref is still tracked
m_componentManager.log( LogService.LOG_DEBUG,
- "Dependency Manager: Static dependency on {0}/{1} is broken", new Object[]
- { m_dependencyMetadata.getName(), m_dependencyMetadata.getInterface() }, null );
+ "Dependency Manager: Static dependency on {0}/{1} is broken", new Object[]
+ {m_dependencyMetadata.getName(), m_dependencyMetadata.getInterface()}, null );
m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE, false );
- m_componentManager.activateInternal();
+ reactivateCount.incrementAndGet();
+ }
+ }
+ public void removedService( ServiceReference<T> serviceReference, RefPair<T> refPair )
+ {
+ if ( reactivateCount.getAndDecrement() > 0 )
+ {
+ //try to reactivate after ref is no longer tracked.
+ m_componentManager.activateInternal();
+
+ }
+ //This is unlikely
+ if (refPair.getServiceObject() != null)
+ {
+ m_componentManager.getActivator().getBundleContext().ungetService( serviceReference );
}
}
@@ -416,12 +449,17 @@
}
}
+ public void removingService( ServiceReference<T> item, RefPair<T> object, int size )
+ {
+ }
+
public void removedService( ServiceReference<T> serviceReference, RefPair<T> refPair )
{
if ( isActive() )
{
if (refs.contains( refPair ))
{
+ //we are tracking the used refs, so we can deactivate here.
m_componentManager.log( LogService.LOG_DEBUG,
"Dependency Manager: Static dependency on {0}/{1} is broken", new Object[]
{ m_dependencyMetadata.getName(), m_dependencyMetadata.getInterface() }, null );
@@ -491,16 +529,20 @@
{
synchronized ( refPair )
{
- if (!m_bindMethods.getBind().getServiceObject( refPair, m_componentManager.getActivator().getBundleContext() ))
+ m_bindMethods.getBind().getServiceObject( refPair, m_componentManager.getActivator().getBundleContext() );
+ }
+ if ( !refPair.isFailed() )
+ {
+ m_componentManager.invokeBindMethod( DependencyManager.this, refPair );
+ if ( this.refPair != null )
{
- //TODO error???
+ m_componentManager.invokeUnbindMethod( DependencyManager.this, this.refPair );
+ closeRefPair();
}
}
- m_componentManager.invokeBindMethod( DependencyManager.this, refPair );
- if ( this.refPair != null )
+ else
{
- m_componentManager.invokeUnbindMethod( DependencyManager.this, this.refPair );
- closeRefPair();
+ m_componentManager.getActivator().registerMissingDependency( DependencyManager.this, serviceReference );
}
this.refPair = refPair;
}
@@ -519,6 +561,10 @@
}
}
+ public void removingService( ServiceReference<T> item, RefPair<T> object, int size )
+ {
+ }
+
public void removedService( ServiceReference<T> serviceReference, RefPair<T> refPair )
{
if (refPair == this.refPair)
@@ -537,7 +583,10 @@
//TODO error???
}
}
- m_componentManager.invokeBindMethod( DependencyManager.this, nextRefPair );
+ if ( !refPair.isFailed() )
+ {
+ m_componentManager.invokeBindMethod( DependencyManager.this, nextRefPair );
+ }
}
if ( isOptional() || nextRefPair != null)
@@ -567,6 +616,10 @@
{
success |= m_bindMethods.getBind().getServiceObject( refPair, m_componentManager.getActivator().getBundleContext() );
}
+ if (refPair.isFailed())
+ {
+ m_componentManager.getActivator().registerMissingDependency( DependencyManager.this, refPair.getRef() );
+ }
this.refPair = refPair;
}
}
@@ -630,6 +683,10 @@
}
}
+ public void removingService( ServiceReference<T> item, RefPair<T> object, int size )
+ {
+ }
+
public void removedService( ServiceReference<T> serviceReference, RefPair<T> refPair )
{
if ( isActive() && refPair == this.refPair )
@@ -1291,12 +1348,6 @@
return null;
}
- private int getServiceReferenceCount()
- {
- ServiceReference<T>[] refs = getFrameworkServiceReferences();
- return refs == null? 0: refs.length;
- }
-
/**
* Returns a <code>ServiceReference</code> instances for a service
@@ -1695,14 +1746,17 @@
new Object[]{ m_dependencyMetadata.getName(), success, refs }, null );
for ( RefPair<T> refPair : refs )
{
- if ( !invokeBindMethod( componentInstance, refPair ) )
+ if ( !refPair.isFailed() )
{
- m_componentManager.log( LogService.LOG_DEBUG,
- "For dependency {0}, failed to invoke bind method on object {1}",
- new Object[] {m_dependencyMetadata.getName(), refPair}, null );
+ if ( !invokeBindMethod( componentInstance, refPair ) )
+ {
+ m_componentManager.log( LogService.LOG_DEBUG,
+ "For dependency {0}, failed to invoke bind method on object {1}",
+ new Object[] {m_dependencyMetadata.getName(), refPair}, null );
+ }
+ success = true;
}
- success = true;
}
return success;
}
@@ -1790,6 +1844,7 @@
}
if ( !isMultiple() )
{
+ //TODO fixme to use tracker
ServiceReference<T>[] refs = getFrameworkServiceReferences();
if ( refs == null )
{
@@ -1807,6 +1862,7 @@
}
//TODO static and dynamic reluctant
RefPair<T> refPair = trackerRef.get().getService( ref );
+ m_bindMethods.getBind().getServiceObject( refPair, m_componentManager.getActivator().getBundleContext() );
m_componentManager.invokeBindMethod( this, refPair );
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/RefPair.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/RefPair.java
index 1b2e1e3..a767d1c 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/RefPair.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/RefPair.java
@@ -30,6 +30,8 @@
private final ServiceReference<T> ref;
private T serviceObject;
+ private boolean failed;
+
public RefPair( ServiceReference<T> ref )
{
this.ref = ref;
@@ -48,8 +50,23 @@
public void setServiceObject( T serviceObject )
{
this.serviceObject = serviceObject;
+ if ( serviceObject != null)
+ {
+ failed = false;
+ }
}
+ public void setFailed( )
+ {
+ this.failed = true;
+ }
+
+ public boolean isFailed()
+ {
+ return failed;
+ }
+
+
@Override
public String toString()
{
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 178f2c5..a71066f 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
@@ -981,6 +981,11 @@
private final LinkedList<S> initial;
/**
+ * counter to show size after removed during remmoving event.
+ */
+ private int pendingRemovals;
+
+ /**
* AbstractTracked constructor.
*/
AbstractTracked() {
@@ -1182,6 +1187,7 @@
*/
void untrack(final S item, final R related) {
final T object;
+ final int size;
synchronized (this) {
if (initial.remove(item)) { /*
* if this item is already in the list
@@ -1208,7 +1214,16 @@
* adding
*/
}
- object = tracked.remove(item); /*
+ object = tracked.get( item );
+ pendingRemovals++;
+ size = tracked.size() - pendingRemovals;
+ }
+ /* Call customizer outside of synchronized region */
+ customizerRemoving(item, related, object, size );
+ synchronized (this) {
+ pendingRemovals--;
+
+ tracked.remove(item); /*
* must remove from tracker before
* calling customizer callback
*/
@@ -1336,6 +1351,8 @@
*/
abstract void customizerModified(final S item, final R related, final T object);
+ abstract void customizerRemoving( final S item, final R related, final T object, int size );
+
/**
* Call the specific customizer removed method. This method must not be
* called while synchronized on this object.
@@ -1441,7 +1458,13 @@
customizer.modifiedService(item, object);
}
- /**
+ @Override
+ void customizerRemoving( ServiceReference<S> item, ServiceEvent related, T object, int size )
+ {
+ customizer.removingService( item, object, size );
+ }
+
+ /**
* Call the specific customizer removed method. This method must not be
* called while synchronized on this object.
*
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceTrackerCustomizer.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceTrackerCustomizer.java
index ac35526..8809db6 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceTrackerCustomizer.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceTrackerCustomizer.java
@@ -81,6 +81,8 @@
*/
public void modifiedService(ServiceReference<S> reference, T service);
+ void removingService( ServiceReference<S> item, T object, int size );
+
/**
* A service tracked by the {@code ServiceTracker} has been removed.
*
@@ -92,4 +94,5 @@
* @param service The service object for the specified referenced service.
*/
public void removedService(ServiceReference<S> reference, T service);
+
}