FELIX-3645 start of separating finding the bound services from creating the impl object. Most itests fail. Some confusion about how bound services are recorded.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1381405 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
index 622ee32..da74b9b 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/BaseMethod.java
@@ -103,6 +103,10 @@
return m_methodName;
}
+ protected final Method getMethod()
+ {
+ return m_method;
+ }
protected final Class getComponentClass()
{
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 4d22578..bcfeb18 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
@@ -21,9 +21,11 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.Map;
import org.apache.felix.scr.impl.Activator;
import org.apache.felix.scr.impl.manager.AbstractComponentManager;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
import org.osgi.service.packageadmin.ExportedPackage;
@@ -40,6 +42,12 @@
private final String m_referenceClassName;
+ private static final int SERVICE_REFERENCE = 1;
+ private static final int SERVICE_OBJECT = 2;
+ private static final int SERVICE_OBJECT_AND_MAP = 3;
+
+ private int m_paramStyle;
+
public BindMethod( final AbstractComponentManager componentManager, final String methodName,
final Class componentClass, final String referenceClassName )
@@ -95,6 +103,7 @@
{
getComponentManager().log( LogService.LOG_DEBUG, "doFindMethod: Found Method " + method, null );
}
+ m_paramStyle = SERVICE_REFERENCE;
return method;
}
}
@@ -122,6 +131,7 @@
method = getServiceObjectMethod( targetClass, parameterClass, acceptPrivate, acceptPackage );
if ( method != null )
{
+ m_paramStyle = SERVICE_OBJECT;
return method;
}
}
@@ -136,6 +146,7 @@
method = getServiceObjectAssignableMethod( targetClass, parameterClass, acceptPrivate, acceptPackage );
if ( method != null )
{
+ m_paramStyle = SERVICE_OBJECT;
return method;
}
}
@@ -154,6 +165,7 @@
method = getServiceObjectWithMapMethod( targetClass, parameterClass, acceptPrivate, acceptPackage );
if ( method != null )
{
+ m_paramStyle = SERVICE_OBJECT_AND_MAP;
return method;
}
}
@@ -169,6 +181,7 @@
acceptPackage );
if ( method != null )
{
+ m_paramStyle = SERVICE_OBJECT_AND_MAP;
return method;
}
}
@@ -541,34 +554,71 @@
return null;
}
+ public AbstractComponentManager.RefPair getServiceObject( ServiceReference ref, BundleContext context )
+ {
+ //??? this resolves which we need.... better way?
+ if ( methodExists() )
+ {
+ if (m_paramStyle == SERVICE_OBJECT || m_paramStyle == SERVICE_OBJECT_AND_MAP) {
+ Object service = context.getService( ref );
+ if ( service == null )
+ {
+ getComponentManager().log(
+ LogService.LOG_WARNING,
+ "Could not get service from ref " + ref, null );
+ return null;
+ }
+
+ return new AbstractComponentManager.RefPair(ref, service);
+ }
+ }
+ return new AbstractComponentManager.RefPair(ref, null);
+// final Class[] paramTypes = getMethod( ).getParameterTypes();
+// final Object[] params = new Object[paramTypes.length];
+// boolean service = false;
+// for ( int i = 0; i < params.length; i++ )
+// {
+// if ( paramTypes[i] == SERVICE_REFERENCE_CLASS )
+// {
+// params[i] = ref;
+// }
+// else if ( paramTypes[i] == MAP_CLASS )
+// {
+// params[i] = new ReadOnlyDictionary( ref );
+// }
+// else
+// {
+// params[i] = context.getService( ref );
+// if ( params[i] == null )
+// {
+// getComponentManager().log(
+// LogService.LOG_WARNING,
+// "Could not get service from ref " + ref, null );
+// return null;
+// }
+// service = true;
+// }
+// }
+//
+// return new AbstractComponentManager.RefPair(params, service);
+ }
protected Object[] getParameters( Method method, Object rawParameter )
{
- final Service service = ( Service ) rawParameter;
- final Class[] paramTypes = method.getParameterTypes();
- final Object[] params = new Object[paramTypes.length];
- for ( int i = 0; i < params.length; i++ )
+ AbstractComponentManager.RefPair refPair = ( AbstractComponentManager.RefPair ) rawParameter; //{ServiceReference, Object}
+ if (m_paramStyle == SERVICE_REFERENCE )
{
- if ( paramTypes[i] == SERVICE_REFERENCE_CLASS )
- {
- params[i] = service.getReference();
- }
- else if ( paramTypes[i] == MAP_CLASS )
- {
- params[i] = new ReadOnlyDictionary( service.getReference() );
- }
- else
- {
- params[i] = service.getInstance();
- if ( params[i] == null )
- {
- throw new IllegalStateException( "Dependency Manager: Service " + service.getReference()
- + " has already gone, will not " + getMethodNamePrefix() );
- }
- }
+ return new Object[] {refPair.getRef()};
}
-
- return params;
+ if (m_paramStyle == SERVICE_OBJECT)
+ {
+ return new Object[] {refPair.getServiceObject()};
+ }
+ if (m_paramStyle == SERVICE_OBJECT_AND_MAP )
+ {
+ return new Object[] {refPair.getServiceObject(), new ReadOnlyDictionary( refPair.getRef() )};
+ }
+ throw new IllegalStateException( "Unexpected m_paramStyle of " + m_paramStyle );
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
index aecaddc..aeaaae9 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
@@ -27,9 +27,11 @@
import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -89,6 +91,9 @@
// The dependency managers that manage every dependency
private final List m_dependencyManagers;
+ //<Map<DependencyManager, Map<ServiceReference, Object[]>>>
+ private final AtomicReferenceWrapper m_dependencies_map;
+
// A reference to the BundleComponentActivator
private BundleComponentActivator m_activator;
@@ -121,11 +126,13 @@
if (JUC_AVAILABLE)
{
m_stateLock = new JLock();
+ m_dependencies_map = new JAtomicReferenceWrapper();
m_serviceRegistration = new JAtomicReferenceWrapper();
}
else
{
m_stateLock = new EDULock();
+ m_dependencies_map = new EDUAtomicReferenceWrapper();
m_serviceRegistration = new EDUAtomicReferenceWrapper();
}
@@ -580,9 +587,9 @@
m_state.enable( this );
}
- final void activateInternal()
+ final boolean activateInternal()
{
- m_state.activate( this );
+ return m_state.activate( this );
}
final void deactivateInternal( int reason )
@@ -678,7 +685,7 @@
protected void registerService( String[] provides )
{
- ServiceRegistration existing = m_serviceRegistration.get();
+ ServiceRegistration existing = ( ServiceRegistration ) m_serviceRegistration.get();
if ( existing == null )
{
log( LogService.LOG_DEBUG, "registering services", null );
@@ -713,7 +720,7 @@
final void unregisterComponentService()
{
- ServiceRegistration sr = m_serviceRegistration.get();
+ ServiceRegistration sr = ( ServiceRegistration ) m_serviceRegistration.get();
if ( sr != null && m_serviceRegistration.compareAndSet( sr, null ) )
{
@@ -722,6 +729,96 @@
}
}
+ protected final boolean collectDependencies()
+ {
+ Map old = ( Map ) m_dependencies_map.get();
+ if ( old != null)
+ {
+ return false;
+ }
+ Class implementationObjectClass = null;
+ try
+ {
+ implementationObjectClass = getActivator().getBundleContext().getBundle().loadClass(
+ getComponentMetadata().getImplementationClassName() );
+ }
+ catch ( ClassNotFoundException e )
+ {
+ log( LogService.LOG_ERROR, "Could not load implementation object class", e );
+ return false;
+ }
+ Map newDeps = new HashMap( );//<DependencyManager, Map<ServiceReference, RefPair>
+ for (Iterator it = m_dependencyManagers.iterator(); it.hasNext(); )
+ {
+ DependencyManager dependencyManager = ( DependencyManager ) it.next();
+
+ dependencyManager.initBindingMethods( implementationObjectClass );
+ if (!dependencyManager.prebind( newDeps) )
+ {
+ //not actually satisfied any longer
+ returnServices( newDeps );
+ return false;
+ }
+ }
+ if ( !m_dependencies_map.compareAndSet( old, newDeps ))
+ {
+ returnServices(newDeps);
+ return false;
+ }
+ return true;
+ }
+
+ private void returnServices( Map deps )
+ {
+ for (Iterator it = deps.values().iterator(); it.hasNext(); )
+ {
+ Map refs = ( Map ) it.next();
+ if ( refs != null )
+ {
+ for (Iterator ri = refs.entrySet().iterator(); ri.hasNext(); )
+ {
+ Map.Entry entry = ( Map.Entry ) ri.next();
+ RefPair args = ( RefPair ) entry.getValue();
+ if ( args.getServiceObject() != null )
+ {
+ getActivator().getBundleContext().ungetService( (ServiceReference) entry.getKey() );
+ }
+ }
+ }
+ }
+ }
+
+ public static class RefPair
+ {
+ private final ServiceReference ref;
+ private Object serviceObject;
+
+ public RefPair( ServiceReference ref, Object serviceObject )
+ {
+ this.ref = ref;
+ this.serviceObject = serviceObject;
+ }
+
+ public ServiceReference getRef()
+ {
+ return ref;
+ }
+
+ public Object getServiceObject()
+ {
+ return serviceObject;
+ }
+
+ public void setServiceObject( Object serviceObject )
+ {
+ this.serviceObject = serviceObject;
+ }
+ }
+
+ Map getDependencyMap()
+ {
+ return ( Map ) m_dependencies_map.get();
+ }
//**********************************************************************************************************
public BundleComponentActivator getActivator()
@@ -739,7 +836,7 @@
final ServiceRegistration getServiceRegistration()
{
- return m_serviceRegistration.get();
+ return ( ServiceRegistration ) m_serviceRegistration.get();
}
@@ -755,6 +852,12 @@
m_dependencyManagers.clear();
}
+ //<DepeendencyManager, Map<ServiceReference, Object[]>>
+ protected Map getParameterMap()
+ {
+ return ( Map ) m_dependencies_map.get();
+ }
+
/**
* Returns <code>true</code> if logging for the given level is enabled.
@@ -1151,9 +1254,10 @@
}
- void activate( AbstractComponentManager acm )
+ boolean activate( AbstractComponentManager acm )
{
log( acm, "activate" );
+ return false;
// throw new IllegalStateException("activate" + this);
}
@@ -1291,14 +1395,19 @@
return m_inst;
}
-
- void activate( AbstractComponentManager acm )
+ /**
+ * returns true if this thread succeeds in activating the component, or the component is not able to be activated.
+ * Returns false if some other thread succeeds in activating the component.
+ * @param acm
+ * @return
+ */
+ boolean activate( AbstractComponentManager acm )
{
if ( !acm.isActivatorActive() )
{
acm.log( LogService.LOG_DEBUG, "Bundle's component activator is not active; not activating component",
null );
- return;
+ return true;
}
acm.log( LogService.LOG_DEBUG, "Activating component", null );
@@ -1308,15 +1417,7 @@
if ( !acm.hasConfiguration() && acm.getComponentMetadata().isConfigurationRequired() )
{
acm.log( LogService.LOG_DEBUG, "Missing required configuration, cannot activate", null );
- return;
- }
-
- // Before creating the implementation object, we are going to
- // test if all the mandatory dependencies are satisfied
- if ( !acm.verifyDependencyManagers( acm.getProperties() ) )
- {
- acm.log( LogService.LOG_DEBUG, "Not all dependencies satisfied, cannot activate", null );
- return;
+ return true;
}
// Before creating the implementation object, we are going to
@@ -1325,7 +1426,15 @@
{
acm.log( LogService.LOG_DEBUG, "Component is not permitted to register all services, cannot activate",
null );
- return;
+ return true;
+ }
+
+ // Before creating the implementation object, we are going to
+ // test if all the mandatory dependencies are satisfied
+ if ( !acm.verifyDependencyManagers( acm.getProperties() ) )
+ {
+ acm.log( LogService.LOG_DEBUG, "Not all dependencies satisfied, cannot activate", null );
+ return true;
}
// set satisfied state before registering the service because
@@ -1348,6 +1457,10 @@
// 4. Call the activate method, if present
if ( ( acm.isImmediate() || acm.getComponentMetadata().isFactory() ) )
{
+ if ( !acm.collectDependencies() )
+ {
+ return false;
+ }
acm.escalateLock( "AbstractComponentManager.Unsatisifed.activate.1" );
try
{
@@ -1365,6 +1478,7 @@
}
}
+ return true;
}
@@ -1605,7 +1719,7 @@
return m_inst;
}
- void activate( AbstractComponentManager acm )
+ boolean activate( AbstractComponentManager acm )
{
throw new IllegalStateException( "activate: " + this );
}
@@ -1735,9 +1849,9 @@
private interface AtomicReferenceWrapper
{
- ServiceRegistration get();
+ Object get();
- boolean compareAndSet(ServiceRegistration expected, ServiceRegistration replacement);
+ boolean compareAndSet(Object expected, Object replacement);
}
@@ -1745,12 +1859,12 @@
{
private final AtomicReference ref = new AtomicReference( );
- public ServiceRegistration get()
+ public Object get()
{
- return ( ServiceRegistration ) ref.get();
+ return ref.get();
}
- public boolean compareAndSet(ServiceRegistration expected, ServiceRegistration replacement)
+ public boolean compareAndSet(Object expected, Object replacement)
{
return ref.compareAndSet( expected, replacement );
}
@@ -1760,12 +1874,12 @@
{
private final EDU.oswego.cs.dl.util.concurrent.SynchronizedRef ref = new EDU.oswego.cs.dl.util.concurrent.SynchronizedRef( null );
- public ServiceRegistration get()
+ public Object get()
{
- return ( ServiceRegistration ) ref.get();
+ return ref.get();
}
- public boolean compareAndSet(ServiceRegistration expected, ServiceRegistration replacement)
+ public boolean compareAndSet(Object expected, Object replacement)
{
return ref.commit( expected, replacement );
}
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 3943fbe..3805221 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,6 +24,7 @@
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -55,11 +56,11 @@
public class DependencyManager implements ServiceListener, Reference
{
// mask of states ok to send events
- private static final int STATE_MASK = Component.STATE_UNSATISFIED
- | Component.STATE_ACTIVE | Component.STATE_REGISTERED | Component.STATE_FACTORY;
+ private static final int STATE_MASK = //Component.STATE_UNSATISFIED |
+ Component.STATE_ACTIVE | Component.STATE_REGISTERED | Component.STATE_FACTORY;
// pseudo service to mark a bound service without actual service instance
- private static final Object BOUND_SERVICE_SENTINEL = new Object();
+// private static final Object BOUND_SERVICE_SENTINEL = new Object();
// the component to which this dependency belongs
private final AbstractComponentManager m_componentManager;
@@ -68,7 +69,7 @@
private final ReferenceMetadata m_dependencyMetadata;
// The map of bound services indexed by their ServiceReference
- private final Map m_bound;
+// private final Map m_bound;
// the number of matching services registered in the system
private volatile int m_size;
@@ -101,7 +102,7 @@
{
m_componentManager = componentManager;
m_dependencyMetadata = dependency;
- m_bound = Collections.synchronizedMap( new HashMap() );
+// m_bound = Collections.synchronizedMap( new HashMap() );
// dump the reference information if DEBUG is enabled
@@ -120,8 +121,12 @@
/**
* Initialize binding methods.
*/
- private void initBindingMethods(Class instanceClass)
+ void initBindingMethods(Class instanceClass)
{
+ if (m_bind != null)
+ {
+ return;
+ }
m_bind = new BindMethod( m_componentManager,
m_dependencyMetadata.getBind(),
instanceClass,
@@ -290,14 +295,34 @@
{ m_dependencyMetadata.getName() }, null );
// immediately try to activate the component (FELIX-2368)
- m_componentManager.activateInternal();
+ boolean handled = m_componentManager.activateInternal();
+ if (!handled)
+ {
+ Map dependenciesMap = m_componentManager.getDependencyMap();
+ if (dependenciesMap != null) {
+ //someone else has managed to activate
+ Map references = ( Map ) dependenciesMap.get( this );
+ if (references == null )
+ {
+ throw new IllegalStateException( "Allegedly active but dependency manager not represented: " + this );
+ }
+ handled = references.containsKey( reference );
+ }
+ }
+ if (handled)
+ {
+ return;
+ }
+ //release our read lock and wait for activation to complete
+ m_componentManager.escalateLock( "DependencyManager.serviceAdded.nothandled.1" );
+ m_componentManager.deescalateLock( "DependencyManager.serviceAdded.nothandled.2" );
}
// otherwise check whether the component is in a state to handle the event
- else if ( handleServiceEvent() )
+ if ( handleServiceEvent() )
{
- // FELIX-1413: if the dependency is static and the component is
+ // FELIX-1413: if the dependency is static and reluctant and the component is
// satisfied (active) added services are not considered until
// the component is reactivated for other reasons.
if ( m_dependencyMetadata.isStatic() )
@@ -308,12 +333,16 @@
"Dependency Manager: Added service {0} is ignored for static reluctant reference", new Object[]
{m_dependencyMetadata.getName()}, null );
}
- else if ( m_dependencyMetadata.isMultiple() ||
- m_bound.isEmpty() ||
- reference.compareTo( m_bound.keySet().iterator().next() ) > 0 )
+ else
{
- m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
- m_componentManager.activateInternal();
+ Map bound = ( Map ) m_componentManager.getDependencyMap().get( this );
+ if ( m_dependencyMetadata.isMultiple() ||
+ bound.isEmpty() ||
+ reference.compareTo( bound.keySet().iterator().next() ) > 0 )
+ {
+ m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
+ m_componentManager.activateInternal();
+ }
}
}
@@ -330,7 +359,8 @@
else if ( !isReluctant() )
{
//dynamic greedy single: bind then unbind
- ServiceReference oldRef = ( ServiceReference ) m_bound.keySet().iterator().next();
+ Map bound = ( Map ) m_componentManager.getDependencyMap().get( this );
+ ServiceReference oldRef = ( ServiceReference ) bound.keySet().iterator().next();
if ( reference.compareTo( oldRef ) > 0 )
{
invokeBindMethod( reference );
@@ -387,7 +417,7 @@
// otherwise check whether the component is in a state to handle the event
else if ( handleServiceEvent() )
{
- // if the dependency is static, we have to reactivate the component
+ // if the dependency is static, we have to deactivate the component
// to "remove" the dependency
if ( m_dependencyMetadata.isStatic() )
{
@@ -416,7 +446,10 @@
{
// if the dependency is mandatory and no replacement is
// available, bind returns false and we deactivate
- if ( !bind() )
+ // bind best matching service
+ ServiceReference ref = getFrameworkServiceReference();
+
+ if ( ref == null )
{
m_componentManager
.log(
@@ -426,6 +459,10 @@
{ m_dependencyMetadata.getName(), m_dependencyMetadata.getInterface() }, null );
m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
}
+ else
+ {
+ invokeBindMethod( ref );
+ }
}
// call the unbind method if one is defined
@@ -741,12 +778,14 @@
*/
private ServiceReference[] getBoundServiceReferences()
{
- if ( m_bound.isEmpty() )
+ Map dependencyMap = m_componentManager.getDependencyMap();
+ Map bound = ( Map ) dependencyMap.get( this );
+ if ( bound.isEmpty() )
{
return null;
}
- return ( ServiceReference[] ) m_bound.keySet().toArray( new ServiceReference[m_bound.size()] );
+ return ( ServiceReference[] ) bound.keySet().toArray( new ServiceReference[bound.size()] );
}
@@ -755,7 +794,8 @@
*/
private boolean isBound()
{
- return !m_bound.isEmpty();
+ Map bound = ( Map ) m_componentManager.getDependencyMap().get( this );
+ return !bound.isEmpty();
}
@@ -773,26 +813,26 @@
* @param serviceReference The reference to the service being marked as
* bound.
*/
- private void bindService( ServiceReference serviceReference )
- {
- m_bound.put( serviceReference, BOUND_SERVICE_SENTINEL );
- }
+// private void bindService( ServiceReference serviceReference )
+// {
+// m_bound.put( serviceReference, BOUND_SERVICE_SENTINEL );
+// }
/**
- * Returns the bound service represented by the given service reference
+ * Returns the RefPair containing the given service reference and the bound service
* or <code>null</code> if this is instance is not currently bound to that
* service.
*
* @param serviceReference The reference to the bound service
*
- * @return the service for the reference or the {@link #BOUND_SERVICE_SENTINEL}
+ * @return RefPair the reference and service for the reference
* if the service is bound or <code>null</code> if the service is not
* bound.
*/
- private Object getBoundService( ServiceReference serviceReference )
+ private AbstractComponentManager.RefPair getBoundService( ServiceReference serviceReference )
{
- return m_bound.get( serviceReference );
+ return ( AbstractComponentManager.RefPair ) (( Map ) m_componentManager.getDependencyMap().get( this )).get(serviceReference);
}
@@ -810,16 +850,16 @@
Object getService( ServiceReference serviceReference )
{
// check whether we already have the service and return that one
- Object service = getBoundService( serviceReference );
- if ( service != null && service != BOUND_SERVICE_SENTINEL )
+ AbstractComponentManager.RefPair refPair = getBoundService( serviceReference );
+ if ( refPair != null && refPair.getServiceObject() != null )
{
- return service;
+ return refPair.getServiceObject();
}
-
+ Object serviceObject = null;
// otherwise acquire the service
try
{
- service = m_componentManager.getActivator().getBundleContext().getService( serviceReference );
+ serviceObject = m_componentManager.getActivator().getBundleContext().getService( serviceReference );
}
catch ( Exception e )
{
@@ -829,17 +869,25 @@
m_componentManager.log( LogService.LOG_ERROR, "Failed getting service {0} ({1}/{2,number,#})", new Object[]
{ m_dependencyMetadata.getName(), m_dependencyMetadata.getInterface(),
serviceReference.getProperty( Constants.SERVICE_ID ) }, e );
- service = null;
+ return null;
}
// keep the service for latter ungetting
- if ( service != null )
+ if ( serviceObject != null )
{
- m_bound.put( serviceReference, service );
+ if (refPair != null)
+ {
+ refPair.setServiceObject( serviceObject );
+ }
+ else
+ {
+ refPair = new AbstractComponentManager.RefPair( serviceReference, serviceObject );
+ ((Map)m_componentManager.getDependencyMap().get( this )) .put( serviceReference, refPair );
+ }
}
// return the acquired service (may be null of course)
- return service;
+ return serviceObject;
}
@@ -850,8 +898,8 @@
void ungetService( ServiceReference serviceReference )
{
// check we really have this service, do nothing if not
- Object service = m_bound.remove( serviceReference );
- if ( service != null && service != BOUND_SERVICE_SENTINEL )
+ AbstractComponentManager.RefPair refPair = ( AbstractComponentManager.RefPair ) ((Map )m_componentManager.getDependencyMap().get( this )).remove( serviceReference );
+ if ( refPair != null && refPair.getServiceObject() != null )
{
BundleComponentActivator activator = m_componentManager.getActivator();
if ( activator != null )
@@ -917,11 +965,11 @@
}
- boolean open( Object instance )
+ boolean open( Object instance, Map parameters )
{
- initBindingMethods( instance.getClass() );
+// initBindingMethods( instance.getClass() );
m_componentInstance = instance;
- return bind();
+ return bind(parameters);
}
@@ -938,13 +986,77 @@
finally
{
m_componentInstance = null;
- m_bind = null;
- m_unbind = null;
- m_bound.clear();
-
+// m_bind = null;
+// m_unbind = null;
+// m_updated = null;
}
}
+ //returns Map<ServiceReference, Object[]>
+ boolean prebind( Map dependencyMap)
+ {
+ // If no references were received, we have to check if the dependency
+ // is optional, if it is not then the dependency is invalid
+ if ( !isSatisfied() )
+ {
+ return false;
+ }
+
+ // if no bind method is configured or if this is a delayed component,
+ // we have nothing to do and just signal success
+ if ( m_dependencyMetadata.getBind() == null )
+ {
+ dependencyMap.put( this, new HashMap( ) );
+ return true;
+ }
+
+ Map result = new HashMap(); //<ServiceReference, Object[]>
+ // 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
+ // flag being set in the loop below
+ boolean success = m_dependencyMetadata.isOptional();
+
+ // Get service reference(s)
+ if ( m_dependencyMetadata.isMultiple() )
+ {
+ // bind all registered services
+ ServiceReference[] refs = getFrameworkServiceReferences();
+ if ( refs != null )
+ {
+ for ( int index = 0; index < refs.length; index++ )
+ {
+ AbstractComponentManager.RefPair refPair = m_bind.getServiceObject( refs[index], m_componentManager.getActivator().getBundleContext() );
+ // success is if we have the minimal required number of services bound
+ if ( refPair != null )
+ {
+ result.put( refs[index], refPair );
+ // of course, we have success if the service is bound
+ success = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ // bind best matching service
+ ServiceReference ref = getFrameworkServiceReference();
+ AbstractComponentManager.RefPair refPair = m_bind.getServiceObject( ref, m_componentManager.getActivator().getBundleContext() );
+ // success is if we have the minimal required number of services bound
+ if ( refPair != null )
+ {
+ result.put( ref, refPair );
+ // of course, we have success if the service is bound
+ success = true;
+ }
+ }
+
+ // success will be true, if the service is optional or if at least
+ // one service was available to be bound (regardless of whether the
+ // bind method succeeded or not)
+ dependencyMap.put( this, result );
+ return success;
+ }
/**
* initializes a dependency. This method binds all of the service
@@ -953,7 +1065,7 @@
* @return true if the dependency is satisfied and at least the minimum
* number of services could be bound. Otherwise false is returned.
*/
- private boolean bind()
+ private boolean bind( Map parameters )
{
// If no references were received, we have to check if the dependency
// is optional, if it is not then the dependency is invalid
@@ -975,38 +1087,12 @@
// flag being set in the loop below
boolean success = m_dependencyMetadata.isOptional();
- // Get service reference(s)
- if ( m_dependencyMetadata.isMultiple() )
+ for ( Iterator i = parameters.entrySet().iterator(); i.hasNext(); )
{
- // bind all registered services
- ServiceReference[] refs = getFrameworkServiceReferences();
- if ( refs != null )
- {
- for ( int index = 0; index < refs.length; index++ )
- {
- // success is if we have the minimal required number of services bound
- if ( invokeBindMethod( refs[index] ) )
- {
- // of course, we have success if the service is bound
- success = true;
- }
- }
- }
+ Map.Entry entry = ( Map.Entry ) i.next();
+ invokeBindMethod( ( AbstractComponentManager.RefPair ) entry.getValue());
+ success = true;
}
- else
- {
- // bind best matching service
- ServiceReference ref = getFrameworkServiceReference();
- if ( ref != null && invokeBindMethod( ref ) )
- {
- // of course, we have success if the service is bound
- success = true;
- }
- }
-
- // success will be true, if the service is optional or if at least
- // one service was available to be bound (regardless of whether the
- // bind method succeeded or not)
return success;
}
@@ -1058,6 +1144,20 @@
}
}
+ private boolean invokeBindMethod( ServiceReference ref )
+ {
+ //event driven, and we already checked this ref is not yet handled.
+ Map dependencyMap = m_componentManager.getDependencyMap();
+ if ( dependencyMap != null )
+ {
+ Map deps = ( Map ) dependencyMap.get( this );
+ BundleContext bundleContext = m_componentManager.getActivator().getBundleContext();
+ AbstractComponentManager.RefPair refPair = m_bind.getServiceObject( ref, bundleContext );
+ deps.put( ref, refPair );
+ return invokeBindMethod( refPair );
+ }
+ return false;
+ }
/**
* Calls the bind method. In case there is an exception while calling the
@@ -1067,15 +1167,15 @@
* If the reference is singular and a service has already been bound to the
* component this method has no effect and just returns <code>true</code>.
*
- * @param ref A ServiceReference with the service that will be bound to the
- * instance object
+ * @param refPair the service reference, service object tuple.
+ *
* @return true if the service should be considered bound. If no bind
* method is found or the method call fails, <code>true</code> is
* returned. <code>false</code> is only returned if the service must
* be handed over to the bind method but the service cannot be
* retrieved using the service reference.
*/
- private boolean invokeBindMethod( final ServiceReference ref )
+ private boolean invokeBindMethod( AbstractComponentManager.RefPair refPair )
{
// The bind method is only invoked if the implementation object is not
// null. This is valid for both immediate and delayed components
@@ -1083,20 +1183,7 @@
{
if ( m_bind != null )
{
- MethodResult result = m_bind.invoke( m_componentInstance, new BindMethod.Service()
- {
- public ServiceReference getReference()
- {
- bindService( ref );
- return ref;
- }
-
-
- public Object getInstance()
- {
- return getService( ref );
- }
- }, MethodResult.VOID );
+ MethodResult result = m_bind.invoke( m_componentInstance, refPair, MethodResult.VOID );
if ( result == null )
{
return false;
@@ -1135,19 +1222,8 @@
// null. This is valid for both immediate and delayed components
if ( m_componentInstance != null )
{
- MethodResult methodResult = m_updated.invoke( m_componentInstance, new BindMethod.Service()
- {
- public ServiceReference getReference()
- {
- return ref;
- }
-
-
- public Object getInstance()
- {
- return getService( ref );
- }
- }, MethodResult.VOID );
+ Object serviceObject = ((Map)m_componentManager.getDependencyMap().get( this )).get( ref );
+ MethodResult methodResult = m_updated.invoke( m_componentInstance, new Object[] {ref, serviceObject}, MethodResult.VOID );
if ( methodResult != null)
{
m_componentManager.setServiceProperties( methodResult );
@@ -1155,7 +1231,7 @@
}
else
{
- // don't care whether we can or cannot call the unbind method
+ // don't care whether we can or cannot call the updated method
// if the component instance has already been cleared by the
// close() method
m_componentManager.log( LogService.LOG_DEBUG,
@@ -1180,19 +1256,8 @@
// null. This is valid for both immediate and delayed components
if ( m_componentInstance != null )
{
- MethodResult methodResult = m_unbind.invoke( m_componentInstance, new BindMethod.Service()
- {
- public ServiceReference getReference()
- {
- return ref;
- }
-
-
- public Object getInstance()
- {
- return getService( ref );
- }
- }, MethodResult.VOID );
+ AbstractComponentManager.RefPair refPair = ( AbstractComponentManager.RefPair ) ((Map )m_componentManager.getDependencyMap().get( this )).get( ref );
+ MethodResult methodResult = m_unbind.invoke( m_componentInstance, refPair, MethodResult.VOID );
if ( methodResult != null )
{
m_componentManager.setServiceProperties( methodResult );
@@ -1334,6 +1399,12 @@
m_targetFilter = null;
}
+ if ( m_componentManager.getDependencyMap() == null)
+ {
+ //component is inactive, no bindings to change.
+ return;
+ }
+ //component is active, we need to check what might have changed.
// check for services to be removed
if ( m_targetFilter != null )
{
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 6989119..5f0d8e0 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
@@ -23,6 +23,7 @@
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import org.apache.felix.scr.impl.BundleComponentActivator;
import org.apache.felix.scr.impl.config.ComponentHolder;
@@ -204,6 +205,7 @@
}
// 3. Bind the target services
+ Map parameters = getParameterMap();
Iterator it = getDependencyManagers();
while ( it.hasNext() )
{
@@ -211,7 +213,8 @@
// creating the instance fails here, so we deactivate and return
// null.
DependencyManager dm = ( DependencyManager ) it.next();
- if ( !dm.open( implementationObject ) )
+ Map params = ( Map ) parameters.get( dm ); //<ServiceReference, RefPair>
+ if ( !dm.open( implementationObject, params ) )
{
log( LogService.LOG_ERROR, "Cannot create component instance due to failure to bind reference {0}",
new Object[]
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java b/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
index 595f61c..aec7ea4 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/helper/BindMethodTest.java
@@ -21,6 +21,7 @@
import junit.framework.TestCase;
+import org.apache.felix.scr.impl.manager.AbstractComponentManager;
import org.apache.felix.scr.impl.manager.ImmediateComponentManager;
import org.apache.felix.scr.impl.manager.components.FakeService;
import org.apache.felix.scr.impl.manager.components.T1;
@@ -29,6 +30,7 @@
import org.apache.felix.scr.impl.manager.components2.T2;
import org.apache.felix.scr.impl.metadata.ComponentMetadata;
import org.easymock.EasyMock;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
@@ -38,32 +40,24 @@
private ServiceReference m_serviceReference;
private FakeService m_serviceInstance;
- private BindMethod.Service m_service;
+ private BundleContext m_context;
public void setUp()
{
m_serviceReference = (ServiceReference) EasyMock.createNiceMock( ServiceReference.class );
m_serviceInstance = (FakeService) EasyMock.createNiceMock( FakeService.class );
- m_service = new BindMethod.Service()
- {
- public ServiceReference getReference()
- {
- return m_serviceReference;
- }
+ m_context = ( BundleContext ) EasyMock.createNiceMock( BundleContext.class );
+ EasyMock.expect( m_context.getService( m_serviceReference ) ).andReturn( m_serviceInstance )
+ .anyTimes();
- public Object getInstance()
- {
- return m_serviceInstance;
- }
- };
EasyMock.expect( m_serviceReference.getPropertyKeys() ).andReturn( new String[]
{ Constants.SERVICE_ID } ).anyTimes();
EasyMock.expect( m_serviceReference.getProperty( Constants.SERVICE_ID ) ).andReturn( "Fake Service" )
.anyTimes();
EasyMock.replay( new Object[]
- { m_serviceReference } );
+ { m_serviceReference, m_context } );
}
@@ -441,7 +435,8 @@
ImmediateComponentManager icm = new ImmediateComponentManager( null, null, metadata );
BindMethod bm = new BindMethod( icm, methodName, component.getClass(),
FakeService.class.getName() );
- bm.invoke( component, m_service, null );
+ AbstractComponentManager.RefPair refPair = bm.getServiceObject( m_serviceReference, m_context );
+ bm.invoke( component, refPair, null );
assertEquals( expectCallPerformed, component.callPerformed );
}
}