You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by fm...@apache.org on 2007/09/17 12:57:53 UTC
svn commit: r576362 -
/felix/trunk/scr/src/main/java/org/apache/felix/scr/DependencyManager.java
Author: fmeschbe
Date: Mon Sep 17 03:57:44 2007
New Revision: 576362
URL: http://svn.apache.org/viewvc?rev=576362&view=rev
Log:
FELIX-368 Service binding odities if (un)bind methods take ServiceReferences
Modified:
felix/trunk/scr/src/main/java/org/apache/felix/scr/DependencyManager.java
Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/DependencyManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/DependencyManager.java?rev=576362&r1=576361&r2=576362&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/DependencyManager.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/DependencyManager.java Mon Sep 17 03:57:44 2007
@@ -48,6 +48,12 @@
private static final int STATE_MASK = AbstractComponentManager.STATE_UNSATISFIED
| AbstractComponentManager.STATE_ACTIVATING | AbstractComponentManager.STATE_ACTIVE
| AbstractComponentManager.STATE_REGISTERED | AbstractComponentManager.STATE_FACTORY;
+
+ // the ServiceReference class instance
+ private static final Class SERVICE_REFERENCE_CLASS = ServiceReference.class;
+
+ // pseudo service to mark a bound service without actual service instance
+ private static final Object BOUND_SERVICE_SENTINEL = new Object();
// the component to which this dependency belongs
private AbstractComponentManager m_componentManager;
@@ -55,15 +61,23 @@
// Reference to the metadata
private ReferenceMetadata m_dependencyMetadata;
- // A flag that defines if the bind method receives a ServiceReference
- private boolean m_bindUsesServiceReference;
-
// The map of bound services indexed by their ServiceReference
private Map m_bound;
// the number of matching services registered in the system
private int m_size;
+ // the bind method
+ private Method m_bind;
+
+ // whether the bind method takes a service reference
+ private boolean m_bindUsesReference;
+
+ // the unbind method
+ private Method m_unbind;
+
+ // whether the unbind method takes a service reference
+ private boolean m_unbindUsesReference;
/**
* Constructor that receives several parameters.
@@ -75,7 +89,6 @@
{
m_componentManager = componentManager;
m_dependencyMetadata = dependency;
- m_bindUsesServiceReference = false;
m_bound = Collections.synchronizedMap( new HashMap() );
// register the service listener
@@ -135,6 +148,10 @@
ungetService( boundRefs[i] );
}
}
+
+ // drop the method references (to help GC)
+ m_bind = null;
+ m_unbind = null;
}
@@ -257,6 +274,13 @@
}
+ // TODO
+ private void bindService( ServiceReference serviceReference )
+ {
+ m_bound.put( serviceReference, BOUND_SERVICE_SENTINEL );
+ }
+
+
/**
* Returns the bound service represented by the given service reference
* or <code>null</code> if this is instance is not currently bound to that
@@ -264,7 +288,9 @@
*
* @param serviceReference The reference to the bound service
*
- * @return the service for the reference if bound or <code>null</code>
+ * @return the service for the reference or the {@link #BOUND_SERVICE_SENTINEL}
+ * if the service is bound or <code>null</code> if the service is not
+ * bound.
*/
private Object getBoundService( ServiceReference serviceReference )
{
@@ -287,7 +313,7 @@
{
// check whether we already have the service and return that one
Object service = getBoundService( serviceReference );
- if ( service != null )
+ if ( service != null && service != BOUND_SERVICE_SENTINEL )
{
return service;
}
@@ -312,7 +338,7 @@
{
// check we really have this service, do nothing if not
Object service = m_bound.remove( serviceReference );
- if ( service != null )
+ if ( service != null && service != BOUND_SERVICE_SENTINEL )
{
m_componentManager.getActivator().getBundleContext().ungetService( serviceReference );
}
@@ -383,30 +409,17 @@
// number of services to bind
for ( int index = 0; index < refs.length; index++ )
{
- // get the service, don't try to bind if the service has gone
- // since we got the service references above
- Object service = getService( refs[index] );
- if ( service == null )
+ // success is if we have the minimal required number of services bound
+ if ( invokeBindMethod( instance, refs[index] ) )
{
- m_componentManager.getActivator().log( LogService.LOG_INFO,
- "Dependency Manager: Service " + refs[index] + " has already gone, not binding",
- m_componentManager.getComponentMetadata(), null );
- continue;
- }
+ // of course, we have success if the service is bound
+ success = true;
- // call the bind method, but ignore success:
- // 112.5.7 If a bind method throws an exception, SCR must log
- // an error message (done in invokeBindMethod) but the activation
- // does not fail
- invokeBindMethod( instance, refs[index], service );
-
- // we have at least on service bound
- success = true;
-
- // if the reference is not multiple, we are already done
- if ( !m_dependencyMetadata.isMultiple() )
- {
- break;
+ // if the reference is not multiple, we are already done
+ if ( !m_dependencyMetadata.isMultiple() )
+ {
+ break;
+ }
}
}
@@ -437,18 +450,7 @@
{
for ( int i = 0; i < boundRefs.length; i++ )
{
- // get the service, don't try to unbind if the service has gone
- // since we got the service references above
- Object service = getBoundService( boundRefs[i] );
- if ( service == null )
- {
- m_componentManager.getActivator().log( LogService.LOG_INFO,
- "Dependency Manager: Service " + boundRefs[i] + " has already gone, not unbinding now",
- m_componentManager.getComponentMetadata(), null );
- continue;
- }
-
- invokeUnbindMethod( instance, boundRefs[i], service );
+ invokeUnbindMethod( instance, boundRefs[i] );
}
}
}
@@ -467,8 +469,6 @@
*/
private Method getBindingMethod( String methodname, Class targetClass, String parameterClassName )
{
- Method method = null;
-
Class parameterClass = null;
// 112.3.1 The method is searched for using the following priority
@@ -479,74 +479,61 @@
// by the reference's interface attribute
try
{
- // Case 1
-
- method = AbstractComponentManager.getMethod( targetClass, methodname, new Class[]
- { ServiceReference.class } );
-
- m_bindUsesServiceReference = true;
+ // Case 1 - ServiceReference parameter
+ return AbstractComponentManager.getMethod( targetClass, methodname, new Class[]
+ { SERVICE_REFERENCE_CLASS }, true );
}
catch ( NoSuchMethodException ex )
{
try
{
- // Case2
-
- m_bindUsesServiceReference = false;
-
+ // Case2 - Service object parameter
parameterClass = m_componentManager.getActivator().getBundleContext().getBundle().loadClass(
parameterClassName );
-
- method = AbstractComponentManager.getMethod( targetClass, methodname, new Class[]
- { parameterClass } );
+ return AbstractComponentManager.getMethod( targetClass, methodname, new Class[]
+ { parameterClass }, true );
}
catch ( NoSuchMethodException ex2 )
{
- // Case 3
- method = null;
+ // Case 3 - Service interface assignement compatible methods
+
+ // Get all potential bind methods
+ Method candidateBindMethods[] = targetClass.getDeclaredMethods();
- // iterate on class hierarchy
- for ( ; method == null && targetClass != null; targetClass = targetClass.getSuperclass() )
+ // Iterate over them
+ for ( int i = 0; i < candidateBindMethods.length; i++ )
{
- // Get all potential bind methods
- Method candidateBindMethods[] = targetClass.getDeclaredMethods();
+ Method method = candidateBindMethods[i];
- // Iterate over them
- for ( int i = 0; method == null && i < candidateBindMethods.length; i++ )
+ // Get the parameters for the current method
+ Class[] parameters = method.getParameterTypes();
+
+ // Select only the methods that receive a single
+ // parameter
+ // and a matching name
+ if ( parameters.length == 1 && method.getName().equals( methodname ) )
{
- Method currentMethod = candidateBindMethods[i];
- // Get the parameters for the current method
- Class[] parameters = currentMethod.getParameterTypes();
+ // Get the parameter type
+ Class theParameter = parameters[0];
- // Select only the methods that receive a single
- // parameter
- // and a matching name
- if ( parameters.length == 1 && currentMethod.getName().equals( methodname ) )
+ // Check if the parameter type is ServiceReference
+ // or is assignable from the type specified by the
+ // reference's interface attribute
+ if ( theParameter.isAssignableFrom( parameterClass ) )
{
- // Get the parameter type
- Class theParameter = parameters[0];
-
- // Check if the parameter type is assignable from
- // the type specified by the reference's interface
- // attribute
- if ( theParameter.isAssignableFrom( parameterClass ) )
+ // Final check: it must be public or protected
+ if ( Modifier.isPublic( method.getModifiers() )
+ || Modifier.isProtected( method.getModifiers() ) )
{
-
- // Final check: it must be public or protected
- if ( Modifier.isPublic( method.getModifiers() )
- || Modifier.isProtected( method.getModifiers() ) )
+ if ( !method.isAccessible() )
{
- if ( !method.isAccessible() )
- {
- method.setAccessible( true );
- }
- method = currentMethod;
-
+ method.setAccessible( true );
}
+ return method;
}
}
}
@@ -560,7 +547,9 @@
}
}
- return method;
+ // if we get here, we have no method, so check the super class
+ targetClass = targetClass.getSuperclass();
+ return ( targetClass != null ) ? getBindingMethod( methodname, targetClass, parameterClassName ) : null;
}
@@ -575,11 +564,13 @@
* @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
+ * @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( Object implementationObject, ServiceReference ref, Object service )
+ 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
@@ -590,33 +581,49 @@
// Get the bind method
m_componentManager.getActivator().log( LogService.LOG_DEBUG,
"getting bind: " + m_dependencyMetadata.getBind(), m_componentManager.getComponentMetadata(), null );
- Method bindMethod = getBindingMethod( m_dependencyMetadata.getBind(), implementationObject.getClass(),
- m_dependencyMetadata.getInterface() );
+ if (m_bind == null) {
+ m_bind = 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 message with the log service, if present, and
- // ignore the method
- m_componentManager.getActivator().log( LogService.LOG_ERROR, "bind() method not found",
- m_componentManager.getComponentMetadata(), null );
- return false;
+ // 112.3.1 If the method is not found , SCR must log an error
+ // message with the log service, if present, and ignore the
+ // method
+ if ( m_bind == null )
+ {
+ m_componentManager.getActivator().log( LogService.LOG_ERROR, "bind() method not found",
+ m_componentManager.getComponentMetadata(), null );
+ return true;
+ }
+
+ // cache whether the bind method takes a reference
+ m_bindUsesReference = SERVICE_REFERENCE_CLASS.equals( m_bind.getParameterTypes()[0] );
}
// Get the parameter
Object parameter;
-
- if ( m_bindUsesServiceReference == false )
+ if ( m_bindUsesReference )
{
- parameter = service;
+ parameter = ref;
+
+ // mark this service as bound using the special sentinel
+ bindService( ref );
}
else
{
- parameter = ref;
+ // get the service, fail binding if the service is not
+ // available (any more)
+ parameter = getService( ref );
+ if ( parameter == null )
+ {
+ m_componentManager.getActivator().log( LogService.LOG_INFO,
+ "Dependency Manager: Service " + ref + " has already gone, not binding",
+ m_componentManager.getComponentMetadata(), null );
+ return false;
+ }
}
// Invoke the method
- bindMethod.invoke( implementationObject, new Object[]
+ m_bind.invoke( implementationObject, new Object[]
{ parameter } );
m_componentManager.getActivator().log( LogService.LOG_DEBUG, "bound: " + getName(),
@@ -627,19 +634,20 @@
catch ( IllegalAccessException ex )
{
// 112.3.1 If the method is not is not declared protected or
- // public, SCR must log an error
- // message with the log service, if present, and ignore the
- // method
+ // public, SCR must log an error message with the log service,
+ // if present, and ignore the method
m_componentManager.getActivator().log( LogService.LOG_ERROR, "bind() method cannot be called",
m_componentManager.getComponentMetadata(), ex );
- return false;
+ return true;
}
catch ( InvocationTargetException ex )
{
+ // 112.5.7 If a bind method throws an exception, SCR must log an
+ // error message containing the exception [...]
m_componentManager.getActivator().log( LogService.LOG_ERROR,
"DependencyManager : exception while invoking " + m_dependencyMetadata.getBind() + "()",
m_componentManager.getComponentMetadata(), ex );
- return false;
+ return true;
}
}
else if ( implementationObject == null && m_componentManager.getComponentMetadata().isImmediate() == false )
@@ -667,7 +675,7 @@
* unbound
* @return true if the call was successful, false otherwise
*/
- private boolean invokeUnbindMethod( Object implementationObject, ServiceReference ref, Object service )
+ private boolean invokeUnbindMethod( Object implementationObject, ServiceReference ref )
{
// The unbind method is only invoked if the implementation object is not
// null. This is valid for both immediate and delayed components
@@ -675,37 +683,47 @@
{
try
{
+ // Get the bind method
m_componentManager.getActivator().log( LogService.LOG_DEBUG,
"getting unbind: " + m_dependencyMetadata.getUnbind(), m_componentManager.getComponentMetadata(),
null );
- Method unbindMethod = getBindingMethod( m_dependencyMetadata.getUnbind(), implementationObject
- .getClass(), m_dependencyMetadata.getInterface() );
+ if ( m_unbind == null )
+ {
+ m_unbind = getBindingMethod( m_dependencyMetadata.getUnbind(), implementationObject.getClass(),
+ m_dependencyMetadata.getInterface() );
- // Recover the object that is bound from the map.
- // Object parameter = m_boundServices.get(ref);
- Object parameter = null;
+ if ( m_unbind == null )
+ {
+ // 112.3.1 If the method is not found, SCR must log an error
+ // message with the log service, if present, and ignore the
+ // method
+ m_componentManager.getActivator().log( LogService.LOG_ERROR, "unbind() method not found",
+ m_componentManager.getComponentMetadata(), null );
+ return true;
+ }
+ // cache whether the unbind method takes a reference
+ m_unbindUsesReference = SERVICE_REFERENCE_CLASS.equals( m_unbind.getParameterTypes()[0] );
+ }
- if ( m_bindUsesServiceReference == true )
+ // Get the parameter
+ Object parameter = null;
+ if ( m_unbindUsesReference )
{
parameter = ref;
}
else
{
- parameter = service;
- }
-
- if ( unbindMethod == null )
- {
- // 112.3.1 If the method is not found , SCR must log an
- // error
- // message with the log service, if present, and ignore the
- // method
- m_componentManager.getActivator().log( LogService.LOG_ERROR, "unbind() method not found",
- m_componentManager.getComponentMetadata(), null );
- return false;
+ parameter = getService( ref );
+ if ( parameter == null )
+ {
+ m_componentManager.getActivator().log( LogService.LOG_INFO,
+ "Dependency Manager: Service " + ref + " has already gone, not unbinding",
+ m_componentManager.getComponentMetadata(), null );
+ return false;
+ }
}
- unbindMethod.invoke( implementationObject, new Object[]
+ m_unbind.invoke( implementationObject, new Object[]
{ parameter } );
m_componentManager.getActivator().log( LogService.LOG_DEBUG, "unbound: " + getName(),
@@ -716,19 +734,20 @@
catch ( IllegalAccessException ex )
{
// 112.3.1 If the method is not is not declared protected or
- // public, SCR must log an error
- // message with the log service, if present, and ignore the
- // method
+ // public, SCR must log an error message with the log service,
+ // if present, and ignore the method
m_componentManager.getActivator().log( LogService.LOG_ERROR, "unbind() method cannot be called",
m_componentManager.getComponentMetadata(), ex );
return false;
}
catch ( InvocationTargetException ex )
{
+ // 112.5.13 If an unbind method throws an exception, SCR must
+ // log an error message containing the exception [...]
m_componentManager.getActivator().log( LogService.LOG_ERROR,
"DependencyManager : exception while invoking " + m_dependencyMetadata.getUnbind() + "()",
m_componentManager.getComponentMetadata(), ex.getCause() );
- return false;
+ return true;
}
finally
{
@@ -778,9 +797,8 @@
// be bound
else if ( m_dependencyMetadata.getBind() != null && ( m_dependencyMetadata.isMultiple() || !isBound() ) )
{
- // get the service (and cache) and invoke the bind method
- Object service = getService( reference );
- invokeBindMethod( m_componentManager.getInstance(), reference, service );
+ // bind the service, getting it if required
+ invokeBindMethod( m_componentManager.getInstance(), reference );
}
}
}
@@ -789,8 +807,7 @@
public void removedService( ServiceReference reference )
{
// check whether we are bound to that service, do nothing if not
- Object service = getBoundService( reference );
- if ( service == null )
+ if ( getBoundService( reference ) == null )
{
return;
}
@@ -842,7 +859,7 @@
// call the unbind method if one is defined
if ( m_dependencyMetadata.getUnbind() != null )
{
- invokeUnbindMethod( instance, reference, service );
+ invokeUnbindMethod( instance, reference );
}
// if binding to another service fails for a singleton