Applied patch (FELIX-243) to add support for service factories to SCR.
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@519003 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/ComponentManagerImpl.java b/scr/src/main/java/org/apache/felix/scr/ComponentManagerImpl.java
index 24c8ef6..d5af234 100644
--- a/scr/src/main/java/org/apache/felix/scr/ComponentManagerImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/ComponentManagerImpl.java
@@ -72,7 +72,7 @@
private ComponentContext m_componentContext = null;
// In case of a delayed component, this holds a reference to the factory
- private DelayedComponentServiceFactory m_delayedComponentServiceFactory;
+ private ServiceFactory m_delayedComponentServiceFactory;
/**
* The constructor receives both the activator and the metadata
@@ -203,8 +203,17 @@
//invalidate();
return;
}
- } else {
- m_delayedComponentServiceFactory = new DelayedComponentServiceFactory();
+ }
+ else if ( m_componentMetadata.getServiceMetadata() != null
+ && m_componentMetadata.getServiceMetadata().isServiceFactory() )
+ {
+ // delayed component is a ServiceFactory service
+ m_delayedComponentServiceFactory = new DelayedServiceFactoryServiceFactory();
+ }
+ else
+ {
+ // delayed component is a standard service
+ m_delayedComponentServiceFactory = new DelayedComponentServiceFactory();
}
// 3. Bind the target services
@@ -495,7 +504,7 @@
for (int index = 0; index < max; index++)
{
- retval = invokeBindMethod(refs[index]);
+ retval = invokeBindMethod(m_implementationObject, refs[index]);
if(retval == false && (max == 1))
{
// There was an exception when calling the bind method
@@ -524,7 +533,7 @@
for (int i = 0; i < allrefs.length; i++)
{
- invokeUnbindMethod((ServiceReference)allrefs[i]);
+ invokeUnbindMethod(m_implementationObject, (ServiceReference)allrefs[i]);
}
}
@@ -662,18 +671,19 @@
* Call 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 object
*
+ * @param implementationObject The object to which the service is bound
* @param ref A ServiceReference with the service that will be bound to the instance object
* @param storeRef A boolean that indicates if the reference must be stored (this is used for the delayed components)
* @return true if the call was successful, false otherwise
**/
- private boolean invokeBindMethod(ServiceReference ref) {
+ private boolean invokeBindMethod(Object implementationObject, ServiceReference ref) {
// The bind method is only invoked if the implementation object is not null. This is valid
// for both immediate and delayed components
- if(m_implementationObject != null) {
+ if(implementationObject != null) {
try {
// Get the bind method
- Method bindMethod = getBindingMethod(m_dependencyMetadata.getBind(), getInstance().getClass(), m_dependencyMetadata.getInterface());
+ Method bindMethod = getBindingMethod(m_dependencyMetadata.getBind(), implementationObject.getClass(), m_dependencyMetadata.getInterface());
if(bindMethod == null){
// 112.3.1 If the method is not found , SCR must log an error
@@ -694,7 +704,7 @@
}
// Invoke the method
- bindMethod.invoke(getInstance(),new Object[] {parameter});
+ bindMethod.invoke(implementationObject, new Object[] {parameter});
// Store the reference
m_boundServicesRefs.add(ref);
@@ -713,7 +723,7 @@
Activator.exception("DependencyManager : exception while invoking "+m_dependencyMetadata.getBind()+"()", m_componentMetadata, ex);
return false;
}
- } else if( m_implementationObject == null && m_componentMetadata.isImmediate() == false) {
+ } else if( implementationObject == null && m_componentMetadata.isImmediate() == false) {
// In the case the implementation object is null and the component is delayed
// then we still have to store the object that is passed to the bind methods
// so that it can be used once the implementation object is created.
@@ -728,20 +738,21 @@
/**
* Call the unbind method
*
+ * @param implementationObject The object from which the service is unbound
* @param ref A service reference corresponding to the service that will be unbound
* @return true if the call was successful, false otherwise
**/
- private boolean invokeUnbindMethod(ServiceReference ref) {
+ private boolean invokeUnbindMethod(Object implementationObject, ServiceReference ref) {
// TODO: assert m_boundServices.contains(ref) == true : "DependencyManager : callUnbindMethod UNBINDING UNKNOWN SERVICE !!!!";
// The unbind method is only invoked if the implementation object is not null. This is valid
// for both immediate and delayed components
- if ( m_implementationObject != null ) {
+ if ( implementationObject != null ) {
try
{
// TODO: me quede aqui por que el unbind method no funciona
Activator.trace("getting unbind: "+m_dependencyMetadata.getUnbind(), m_componentMetadata);
- Method unbindMethod = getBindingMethod(m_dependencyMetadata.getUnbind(), getInstance().getClass(), m_dependencyMetadata.getInterface());
+ Method unbindMethod = getBindingMethod(m_dependencyMetadata.getUnbind(), implementationObject.getClass(), m_dependencyMetadata.getInterface());
// Recover the object that is bound from the map.
//Object parameter = m_boundServices.get(ref);
@@ -761,7 +772,7 @@
return false;
}
- unbindMethod.invoke(getInstance(),new Object [] {parameter});
+ unbindMethod.invoke(implementationObject, new Object [] {parameter});
m_boundServicesRefs.remove(ref);
@@ -780,7 +791,7 @@
return false;
}
- } else if( m_implementationObject == null && m_componentMetadata.isImmediate() == false) {
+ } else if( implementationObject == null && m_componentMetadata.isImmediate() == false) {
// In the case the implementation object is null and the component is delayed
// then we still have to store the object that is passed to the bind methods
// so that it can be used once the implementation object is created.
@@ -846,7 +857,7 @@
// Release references to the service, call unbinder method
// and eventually request service unregistration
- invokeUnbindMethod(evt.getServiceReference());
+ invokeUnbindMethod(m_implementationObject, evt.getServiceReference());
// The only thing we need to do here is check if we can reinitialize
// once the bound services becomes zero. This tries to repair dynamic
@@ -897,7 +908,7 @@
// Otherwise only bind if bind services is zero, which captures the 0..1 case
if (m_dependencyMetadata.isMultiple() || m_boundServicesRefs.size() == 0)
{
- invokeBindMethod(evt.getServiceReference());
+ invokeBindMethod(m_implementationObject, evt.getServiceReference());
}
}
}
@@ -1057,59 +1068,77 @@
}
/**
- * This class is a ServiceFactory that is used when a delayed component is created
+ * This class is a ServiceFactory that is used when a delayed component is created.
+ * This class returns the same service object instance for all bundles.
*
*/
class DelayedComponentServiceFactory implements ServiceFactory {
- public Object getService(Bundle arg0, ServiceRegistration arg1) {
+ public Object getService(Bundle bundle, ServiceRegistration registration) {
Activator.trace("DelayedComponentServiceFactory.getService()", m_componentMetadata);
// When the getServiceMethod is called, the implementation object must be created
-
+ // unless another bundle has already retrievd it
+
+ if (m_implementationObject == null) {
+ m_componentContext = new ComponentContextImpl(null);
+ m_implementationObject = createImplementationObject( m_componentContext );
+ }
+
+ return m_implementationObject;
+ }
+
+ public void ungetService(Bundle bundle, ServiceRegistration registration, Object object) {
+ // nothing to do here, delayed components are deactivated when
+ // the component is deactivated and not when any bundle releases
+ // the service
+ }
+
+ protected Object createImplementationObject(ComponentContext componentContext) {
+ Object implementationObject;
+
// 1. Load the component implementation class
// 2. Create the component instance and component context
// If the component is not immediate, this is not done at this moment
- try
- {
- // 112.4.4 The class is retrieved with the loadClass method of the component's bundle
- Class c = m_activator.getBundleContext().getBundle().loadClass(m_componentMetadata.getImplementationClassName());
-
- // 112.4.4 The class must be public and have a public constructor without arguments so component instances
- // may be created by the SCR with the newInstance method on Class
- m_componentContext = new ComponentContextImpl(arg0);
- m_implementationObject = c.newInstance();
- }
- catch (Exception ex)
- {
- // TODO: manage this exception when implementation object cannot be created
- Activator.exception("Error during instantiation of the implementation object",m_componentMetadata,ex);
- deactivate();
- //invalidate();
- return null;
- }
-
-
- // 3. Bind the target services
- Iterator it = m_dependencyManagers.iterator();
+ try
+ {
+ // 112.4.4 The class is retrieved with the loadClass method of the component's bundle
+ Class c = m_activator.getBundleContext().getBundle().loadClass(m_componentMetadata.getImplementationClassName());
+
+ // 112.4.4 The class must be public and have a public constructor without arguments so component instances
+ // may be created by the SCR with the newInstance method on Class
+ implementationObject = c.newInstance();
+ }
+ catch (Exception ex)
+ {
+ // TODO: manage this exception when implementation object cannot be created
+ Activator.exception("Error during instantiation of the implementation object",m_componentMetadata,ex);
+ deactivate();
+ //invalidate();
+ return null;
+ }
+
+
+ // 3. Bind the target services
+ Iterator it = m_dependencyManagers.iterator();
- while ( it.hasNext() )
- {
- DependencyManager dm = (DependencyManager)it.next();
- Iterator bound = dm.m_boundServicesRefs.iterator();
- while ( bound.hasNext() ) {
- ServiceReference nextRef = (ServiceReference) bound.next();
- dm.invokeBindMethod(nextRef);
- }
- }
-
- // 4. Call the activate method, if present
+ while ( it.hasNext() )
+ {
+ DependencyManager dm = (DependencyManager)it.next();
+ Iterator bound = dm.m_boundServicesRefs.iterator();
+ while ( bound.hasNext() ) {
+ ServiceReference nextRef = (ServiceReference) bound.next();
+ dm.invokeBindMethod(implementationObject, nextRef);
+ }
+ }
+
+ // 4. Call the activate method, if present
// Search for the activate method
- try {
- Method activateMethod = getMethod(m_implementationObject.getClass(), "activate", new Class[]{ComponentContext.class});
- activateMethod.invoke(m_implementationObject, new Object[]{m_componentContext});
- }
- catch(NoSuchMethodException ex) {
+ try {
+ Method activateMethod = getMethod(implementationObject.getClass(), "activate", new Class[]{ComponentContext.class});
+ activateMethod.invoke(implementationObject, new Object[]{componentContext});
+ }
+ catch(NoSuchMethodException ex) {
// We can safely ignore this one
Activator.trace("activate() method is not implemented", m_componentMetadata);
}
@@ -1120,15 +1149,100 @@
catch(InvocationTargetException ex) {
// TODO: 112.5.8 If the activate method throws an exception, SCR must log an error message
// containing the exception with the Log Service
- Activator.exception("The activate method has thrown and exception", m_componentMetadata, ex);
+ Activator.exception("The activate method has thrown an exception", m_componentMetadata, ex);
}
-
- return m_implementationObject;
- }
+
+ return implementationObject;
+ }
+ }
- public void ungetService(Bundle arg0, ServiceRegistration arg1, Object arg2) {
- // TODO Auto-generated method stub
- }
+ /**
+ * This class is a ServiceFactory that is used when a delayed component is created
+ * for a service factory service
+ *
+ */
+ class DelayedServiceFactoryServiceFactory extends DelayedComponentServiceFactory
+ {
+
+ // we do not have to maintain references to the actual service
+ // instances as those are handled by the ServiceManager and given
+ // to the ungetService method when the bundle releases the service
+
+ // maintain the map of componentContext objects created for the
+ // service instances
+ private IdentityHashMap componentContexts = new IdentityHashMap();
+
+ public Object getService( Bundle bundle, ServiceRegistration registration )
+ {
+
+ Activator.trace( "DelayedServiceFactoryServiceFactory.getService()", m_componentMetadata );
+ // When the getServiceMethod is called, the implementation object must be created
+
+ // private ComponentContext and implementation instances
+ ComponentContext componentContext = new ComponentContextImpl( bundle );
+ Object implementationObject = createImplementationObject( componentContext );
+
+ // register the components component context
+ componentContexts.put( implementationObject, componentContext );
+
+ return implementationObject;
+ }
+
+ public void ungetService( Bundle bundle, ServiceRegistration registration, Object implementationObject )
+ {
+ Activator.trace( "DelayedServiceFactoryServiceFactory.ungetService()", m_componentMetadata );
+ // When the ungetServiceMethod is called, the implementation object must be deactivated
+
+ // private ComponentContext and implementation instances
+ ComponentContext componentContext = ( ComponentContext ) componentContexts.remove( implementationObject );
+ deactivateImplementationObject( implementationObject, componentContext );
+ }
+
+ protected void deactivateImplementationObject( Object implementationObject, ComponentContext componentContext )
+ {
+ // 1. Call the deactivate method, if present
+ // Search for the activate method
+ try
+ {
+ Method deactivateMethod = getMethod( implementationObject.getClass(), "deactivate", new Class[]
+ { ComponentContext.class } );
+ deactivateMethod.invoke( implementationObject, new Object[]
+ { componentContext } );
+ }
+ catch ( NoSuchMethodException ex )
+ {
+ // We can safely ignore this one
+ Activator.trace( "deactivate() method is not implemented", m_componentMetadata );
+ }
+ catch ( IllegalAccessException ex )
+ {
+ // Ignored, but should it be logged?
+ Activator.trace( "deactivate() method cannot be called", m_componentMetadata );
+ }
+ catch ( InvocationTargetException ex )
+ {
+ // TODO: 112.5.12 If the deactivate method throws an exception, SCR must log an error message
+ // containing the exception with the Log Service and continue
+ Activator.exception( "The deactivate method has thrown an exception", m_componentMetadata, ex );
+ }
+
+ // 2. Unbind any bound services
+ Iterator it = m_dependencyManagers.iterator();
+
+ while ( it.hasNext() )
+ {
+ DependencyManager dm = ( DependencyManager ) it.next();
+ Iterator bound = dm.m_boundServicesRefs.iterator();
+ while ( bound.hasNext() )
+ {
+ ServiceReference nextRef = ( ServiceReference ) bound.next();
+ dm.invokeUnbindMethod( implementationObject, nextRef );
+ }
+ }
+
+ // 3. Release all references
+ // nothing to do, we keep no references on per-Bundle services
+ }
}
/**