FELIX-3557 resolve-circular-dependencies-later implementation
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1398942 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java b/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
index 9f1d6d0..1be5427 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
@@ -35,11 +35,13 @@
import org.apache.felix.scr.impl.config.ScrConfiguration;
import org.apache.felix.scr.impl.helper.Logger;
import org.apache.felix.scr.impl.manager.AbstractComponentManager;
+import org.apache.felix.scr.impl.manager.DependencyManager;
import org.apache.felix.scr.impl.metadata.ComponentMetadata;
import org.apache.felix.scr.impl.metadata.XmlHandler;
import org.apache.felix.scr.impl.parser.KXml2SAXParser;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentException;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker;
@@ -597,4 +599,13 @@
}
}
+ public void missingServicePresent( ServiceReference serviceReference )
+ {
+ m_componentRegistry.missingServicePresent( serviceReference, m_componentActor );
+ }
+
+ public void registerMissingDependency( DependencyManager dependencyManager, ServiceReference serviceReference )
+ {
+ m_componentRegistry.registerMissingDependency(dependencyManager, serviceReference);
+ }
}
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 deb4e99..0e2ab5c 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
@@ -38,6 +38,7 @@
import org.apache.felix.scr.impl.manager.AbstractComponentManager;
import org.apache.felix.scr.impl.manager.ComponentFactoryImpl;
import org.apache.felix.scr.impl.manager.ConfigurationComponentFactoryImpl;
+import org.apache.felix.scr.impl.manager.DependencyManager;
import org.apache.felix.scr.impl.metadata.ComponentMetadata;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
@@ -47,6 +48,7 @@
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.ComponentException;
@@ -128,6 +130,8 @@
// the ConfigurationAdmin service
private ConfigurationSupport configurationSupport;
+ private final Map m_missingDependencies = new HashMap( );
+
protected ComponentRegistry( BundleContext context )
{
m_bundleContext = context;
@@ -648,4 +652,41 @@
this.configurationSupport = null;
}
}
+
+ public void missingServicePresent( final ServiceReference serviceReference, ComponentActorThread actor )
+ {
+ final List dependencyManagers = ( List ) m_missingDependencies.remove( serviceReference );
+ if ( dependencyManagers != null )
+ {
+ actor.schedule( new Runnable()
+ {
+
+ public void run()
+ {
+ for ( Iterator i = dependencyManagers.iterator(); i.hasNext(); )
+ {
+ DependencyManager dm = ( DependencyManager ) i.next();
+ dm.invokeBindMethodLate( serviceReference );
+ }
+ }
+ } );
+ }
+ }
+
+ public synchronized void registerMissingDependency( DependencyManager dependencyManager, ServiceReference serviceReference )
+ {
+ //check that the service reference is from scr
+ if ( serviceReference.getProperty( ComponentConstants.COMPONENT_NAME ) == null || serviceReference.getProperty( ComponentConstants.COMPONENT_ID ) == null )
+ {
+ return;
+ }
+ List dependencyManagers = ( List ) m_missingDependencies.get( serviceReference );
+ if ( dependencyManagers == null )
+ {
+ dependencyManagers = new ArrayList();
+ m_missingDependencies.put( serviceReference, dependencyManagers );
+ }
+ dependencyManagers.add( dependencyManager );
+ }
+
}
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 d15fa77..27f74d4 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
@@ -1059,7 +1059,7 @@
return true;
}
- Map result = new HashMap(); //<ServiceReference, Object[]>
+ Map result = new HashMap(); //<ServiceReference, RefPair>
// 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
@@ -1083,6 +1083,10 @@
// of course, we have success if the service is bound
success = true;
}
+ else
+ {
+ m_componentManager.getActivator().registerMissingDependency(this, refs[index]);
+ }
}
}
}
@@ -1100,6 +1104,10 @@
// of course, we have success if the service is bound
success = true;
}
+ else if ( isOptional() )
+ {
+ m_componentManager.getActivator().registerMissingDependency(this, ref);
+ }
}
}
@@ -1249,6 +1257,33 @@
}
}
+ public void invokeBindMethodLate( final ServiceReference ref )
+ {
+ if ( !isSatisfied() )
+ {
+ return;
+ }
+ if ( !isMultiple() )
+ {
+ ServiceReference[] refs = getFrameworkServiceReferences();
+ if ( refs == null )
+ {
+ return; // should not happen, we have one!
+ }
+ // find the service with the highest ranking
+ for ( int i = 1; i < refs.length; i++ )
+ {
+ ServiceReference test = refs[i];
+ if ( test.compareTo( ref ) > 0 )
+ {
+ return; //another ref is better
+ }
+ }
+ }
+ //TODO static and dynamic reluctant
+ m_componentManager.invokeBindMethod( this, ref );
+ }
+
/**
* Calls the bind method. In case there is an exception while calling the
* bind method, the service is not considered to be bound to the instance
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 1795564..41b1c24 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
@@ -78,7 +78,6 @@
// this is null, if none exist or none are provided
private Dictionary m_configurationProperties;
-
/**
* The constructor receives both the activator and the metadata
*
@@ -132,6 +131,9 @@
m_componentContext = tmpContext;
m_implementationObject = tmpComponent;
log( LogService.LOG_DEBUG, "Set implementation object for component {0}", new Object[] { getName() }, null );
+
+ //notify that component was successfully created so any optional circular dependencies can be retried
+ getActivator().missingServicePresent(getServiceReference());
}
return true;
}
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 38e4d8d..b548fc1 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
@@ -86,7 +86,7 @@
TestCase.assertNotNull( componentB );
TestCase.assertEquals( Component.STATE_ACTIVE, componentB.getState() );
B b = ( B ) componentB.getComponentInstance().getInstance();
- assertEquals( 0, b.getAs().size() );
+ assertEquals( 1, b.getAs().size() );
}
/**
* A > 1.1 > B > 0..n > A Both should start (B first), and B should have an A reference.
@@ -130,11 +130,12 @@
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..n > A Both should start, but B should not have an A reference.
@@ -164,11 +165,11 @@
Object serviceA = bundleContext.getService( serviceReferenceA );
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
@@ -207,7 +208,7 @@
TestCase.assertNotNull( componentB );
TestCase.assertEquals( Component.STATE_ACTIVE, componentB.getState() );
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 (B first), and B should have an A reference.