FELIX-925 Add support for new activate/deactivate method signatures and
for the deactivation reason
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@792527 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/AbstractComponentManager.java
index 759014d..444b9a9 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/AbstractComponentManager.java
@@ -31,6 +31,7 @@
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.ComponentInstance;
import org.osgi.service.log.LogService;
@@ -133,11 +134,10 @@
acm.getComponentMetadata(), null);
}
- void deactivateInternal( AbstractComponentManager acm )
+ void deactivateInternal( AbstractComponentManager acm, int reason )
{
- acm.log( LogService.LOG_DEBUG,
- "Current state: " + m_name + ", Event: deactivate",
- acm.getComponentMetadata(), null );
+ acm.log( LogService.LOG_DEBUG, "Current state: " + m_name + ", Event: deactivate (reason: " + reason + ")",
+ acm.getComponentMetadata(), null );
}
void disposeInternal( AbstractComponentManager acm )
@@ -361,17 +361,26 @@
return sr == null ? null : sr.getReference();
}
- void deactivateInternal( AbstractComponentManager acm )
+ void deactivateInternal( AbstractComponentManager acm, int reason )
{
acm.changeState(Deactivating.getInstance());
ComponentMetadata componentMetadata = acm.getComponentMetadata();
acm.log( LogService.LOG_DEBUG, "Deactivating component", componentMetadata, null );
- acm.unregisterComponentService();
- acm.deleteComponent();
- acm.changeState( Unsatisfied.getInstance() );
+ // catch any problems from deleting the component to prevent the
+ // component to remain in the deactivating state !
+ try
+ {
+ acm.unregisterComponentService();
+ acm.deleteComponent( reason );
+ }
+ catch ( Throwable t )
+ {
+ acm.log( LogService.LOG_WARNING, "Component deactivation threw an exception", componentMetadata, t );
+ }
+ acm.changeState( Unsatisfied.getInstance() );
acm.log( LogService.LOG_DEBUG, "Component deactivated", componentMetadata, null );
}
}
@@ -398,7 +407,7 @@
}
else
{
- deactivateInternal( dcm );
+ deactivateInternal( dcm, ComponentConstants.DEACTIVATION_REASON_UNSPECIFIED );
return null;
}
}
@@ -496,12 +505,18 @@
{
public void doRun()
{
- deactivateInternal();
+ deactivateInternal( ComponentConstants.DEACTIVATION_REASON_DISABLED );
disableInternal();
}
});
}
+ // implements the ComponentInstance.dispose() method
+ public void dispose()
+ {
+ dispose( ComponentConstants.DEACTIVATION_REASON_DISPOSED );
+ }
+
/**
* Disposes off this component deactivating and disabling it first as
* required. After disposing off the component, it may not be used anymore.
@@ -511,9 +526,9 @@
* method has to actually complete before other actions like bundle stopping
* may continue.
*/
- public void dispose()
+ public void dispose( int reason )
{
- disposeInternal();
+ disposeInternal( reason );
}
//---------- Component interface ------------------------------------------
@@ -604,14 +619,14 @@
m_state.activateInternal( this );
}
- synchronized final void deactivateInternal()
+ synchronized final void deactivateInternal( int reason )
{
- m_state.deactivateInternal( this );
+ m_state.deactivateInternal( this, reason );
}
- synchronized final void disposeInternal()
+ synchronized final void disposeInternal( int reason )
{
- m_state.deactivateInternal( this );
+ m_state.deactivateInternal( this, reason );
// For the sake of the performance(no need to loadDependencyManagers again),
// the disable transition is integrated into the destroy transition.
// That is to say, state "Enabled" goes directly into state "Desctroyed"
@@ -655,7 +670,7 @@
*/
protected abstract boolean createComponent();
- protected abstract void deleteComponent();
+ protected abstract void deleteComponent( int reason );
/**
* Returns the service object to be registered if the service element is
@@ -710,7 +725,7 @@
m_serviceRegistration = registerService();
}
- protected void unregisterComponentService()
+ protected final void unregisterComponentService()
{
if ( m_serviceRegistration != null )
@@ -769,11 +784,10 @@
* activation the new configuration data is retrieved from the Configuration
* Admin Service.
*/
- public final void reconfigure()
+ public final void reconfigure( final int reason )
{
- log( LogService.LOG_DEBUG, "Deactivating and Activating to reconfigure",
- m_componentMetadata, null );
- reactivate();
+ log( LogService.LOG_DEBUG, "Deactivating and Activating to reconfigure", m_componentMetadata, null );
+ reactivate( reason );
}
/**
@@ -783,16 +797,17 @@
* This method schedules the deactivation and reactivation for asynchronous
* execution.
*/
- public final void reactivate()
+ public final void reactivate( final int reason )
{
- getActivator().schedule(new ComponentActivatorTask( "Reactivate", this ) {
+ getActivator().schedule( new ComponentActivatorTask( "Reactivate", this )
+ {
public void doRun()
{
- deactivateInternal();
+ deactivateInternal( reason );
activateInternal();
}
- });
+ } );
}
public String toString() {
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/Activator.java b/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
index 556bf5e..5d15d49 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
@@ -32,6 +32,7 @@
import org.osgi.framework.BundleEvent;
import org.osgi.framework.Constants;
import org.osgi.framework.SynchronousBundleListener;
+import org.osgi.service.component.ComponentConstants;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker;
@@ -261,7 +262,7 @@
{
try
{
- ga.dispose();
+ ga.dispose( ComponentConstants.DEACTIVATION_REASON_BUNDLE_STOPPED );
}
catch ( Exception e )
{
@@ -280,7 +281,7 @@
BundleComponentActivator ga = ( BundleComponentActivator ) it.next();
try
{
- ga.dispose();
+ ga.dispose( ComponentConstants.DEACTIVATION_REASON_DISPOSED );
}
catch ( Exception e )
{
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 273106e..6d44ca3 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
@@ -252,7 +252,7 @@
* Dispose of this component activator instance and all the component
* managers.
*/
- void dispose()
+ void dispose( int reason )
{
if ( m_context == null )
{
@@ -271,7 +271,7 @@
try
{
m_managers.remove( manager );
- manager.dispose();
+ manager.dispose( reason );
}
catch ( Exception e )
{
@@ -337,7 +337,7 @@
* configuration data for components managed by this activator or
* <code>null</code> if no Configuration Admin Service is available in the
* framework.
- */
+ */
protected ConfigurationAdmin getConfigurationAdmin()
{
return ( ConfigurationAdmin ) m_configurationAdmin.getService();
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ComponentFactoryImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/ComponentFactoryImpl.java
index 7c94c27..3c79515 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ComponentFactoryImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ComponentFactoryImpl.java
@@ -48,7 +48,7 @@
// Actually we only use the identity key stuff, but there is
// no IdentityHashSet and HashSet internally uses a HashMap anyway
- private Map m_createdComponents;
+ private final Map m_createdComponents;
ComponentFactoryImpl( BundleComponentActivator activator, ComponentMetadata metadata,
@@ -76,9 +76,14 @@
}
- protected void deleteComponent()
+ protected void deleteComponent( int reason )
{
- // nothing to delete
+ // though we have nothing to delete really, we have to remove all
+ // references to the components created for configuration
+ m_createdComponents.clear();
+ if (m_configuredServices != null) {
+ m_configuredServices = null;
+ }
}
@@ -178,7 +183,7 @@
log( LogService.LOG_DEBUG, "Disposing component after configuration deletion", getComponentMetadata(),
null );
- disposeComponentManager( cm );
+ disposeComponentManager( cm, ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED );
}
}
@@ -239,7 +244,7 @@
return cm;
}
- private void disposeComponentManager( ImmediateComponentManager cm )
+ private void disposeComponentManager( ImmediateComponentManager cm, int reason )
{
// remove from created components
m_createdComponents.remove( cm );
@@ -248,6 +253,6 @@
getActivator().getInstanceReferences().remove( cm );
// finally dispose it
- cm.dispose();
+ cm.dispose( reason );
}
}
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 5866520..148a0ff 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
@@ -155,7 +155,7 @@
{
cm = getComponent( factoryPid );
}
-
+
if (cm == null) {
// this configuration is not for a SCR component
return;
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/DelayedComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/DelayedComponentManager.java
index e79d1cf..f959fa5 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/DelayedComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/DelayedComponentManager.java
@@ -50,12 +50,12 @@
}
- protected void deleteComponent()
+ protected void deleteComponent( int reason )
{
// only have to delete, if there is actually an instance
if ( getInstance() != null )
{
- super.deleteComponent();
+ super.deleteComponent( reason );
}
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/DependencyManager.java b/scr/src/main/java/org/apache/felix/scr/impl/DependencyManager.java
index 2107196..6033e6a 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/DependencyManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/DependencyManager.java
@@ -37,6 +37,7 @@
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentConstants;
import org.osgi.service.log.LogService;
@@ -228,7 +229,7 @@
+ m_dependencyMetadata.getName() + " registered, reactivate component", m_componentManager
.getComponentMetadata(), null );
- m_componentManager.reactivate();
+ m_componentManager.reactivate( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
}
else
{
@@ -242,7 +243,7 @@
+ m_dependencyMetadata.getName() + " with higher ranking registered, reactivate component",
m_componentManager.getComponentMetadata(), null );
- m_componentManager.reactivate();
+ m_componentManager.reactivate( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
}
}
}
@@ -324,7 +325,7 @@
+ " not satisfied", m_componentManager.getComponentMetadata(), null );
// deactivate the component now
- m_componentManager.deactivateInternal();
+ m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
}
// if the dependency is static, we have to reactivate the component
@@ -336,8 +337,8 @@
m_componentManager.log( LogService.LOG_DEBUG, "Dependency Manager: Static dependency on "
+ m_dependencyMetadata.getName() + "/" + m_dependencyMetadata.getInterface() + " is broken",
m_componentManager.getComponentMetadata(), null );
- m_componentManager.deactivateInternal();
- m_componentManager.activate();
+ m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
+ m_componentManager.activate();
}
catch ( Exception ex )
{
@@ -362,7 +363,7 @@
"Dependency Manager: Deactivating component due to mandatory dependency on "
+ m_dependencyMetadata.getName() + "/" + m_dependencyMetadata.getInterface()
+ " not satisfied", m_componentManager.getComponentMetadata(), null );
- m_componentManager.deactivateInternal();
+ m_componentManager.deactivateInternal( ComponentConstants.DEACTIVATION_REASON_REFERENCE );
// abort here we do not need to do more
return;
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ImmediateComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/ImmediateComponentManager.java
index f56ea18..10bc7b1 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ImmediateComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ImmediateComponentManager.java
@@ -24,9 +24,7 @@
import java.util.Dictionary;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
-import org.osgi.framework.BundleContext;
import org.osgi.service.cm.Configuration;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.ComponentContext;
@@ -39,38 +37,6 @@
*/
class ImmediateComponentManager extends AbstractComponentManager
{
- private static final Class COMPONENT_CONTEXT_CLASS = ComponentContext.class;
-
- private static final Class BUNDLE_CONTEXT_CLASS = BundleContext.class;
-
- private static final Class MAP_CLASS = Map.class;
-
- // this is an internal field made available only to the unit tests
- static final Class[][] ACTIVATE_PARAMETER_LIST = {
- { COMPONENT_CONTEXT_CLASS },
- { BUNDLE_CONTEXT_CLASS },
- { MAP_CLASS },
-
- { COMPONENT_CONTEXT_CLASS, BUNDLE_CONTEXT_CLASS },
- { COMPONENT_CONTEXT_CLASS, MAP_CLASS },
-
- { BUNDLE_CONTEXT_CLASS, COMPONENT_CONTEXT_CLASS },
- { BUNDLE_CONTEXT_CLASS, MAP_CLASS },
-
- { MAP_CLASS, COMPONENT_CONTEXT_CLASS },
- { MAP_CLASS, BUNDLE_CONTEXT_CLASS },
-
- { COMPONENT_CONTEXT_CLASS, BUNDLE_CONTEXT_CLASS, MAP_CLASS },
- { COMPONENT_CONTEXT_CLASS, MAP_CLASS, BUNDLE_CONTEXT_CLASS },
-
- { BUNDLE_CONTEXT_CLASS, COMPONENT_CONTEXT_CLASS, MAP_CLASS },
- { BUNDLE_CONTEXT_CLASS, MAP_CLASS, COMPONENT_CONTEXT_CLASS },
-
- { MAP_CLASS, COMPONENT_CONTEXT_CLASS, BUNDLE_CONTEXT_CLASS },
- { MAP_CLASS, BUNDLE_CONTEXT_CLASS, COMPONENT_CONTEXT_CLASS },
-
- {}
- };
// The object that implements the service and that is bound to other services
private Object m_implementationObject;
@@ -124,10 +90,10 @@
* Before doing real disposal, we also have to unregister the managed
* service which was registered when the instance was created.
*/
- public synchronized void dispose()
+ public synchronized void dispose( final int reason )
{
// really dispose off this manager instance
- disposeInternal();
+ disposeInternal( reason );
}
@@ -155,9 +121,9 @@
}
- protected void deleteComponent()
+ protected void deleteComponent( int reason )
{
- disposeImplementationObject( m_implementationObject, m_componentContext );
+ disposeImplementationObject( m_implementationObject, m_componentContext, reason );
m_implementationObject = null;
m_componentContext = null;
m_properties = null;
@@ -230,11 +196,12 @@
// get the method
if ( activateMethod == ReflectionHelper.SENTINEL )
{
- activateMethod = getMethod( implementationObject, getComponentMetadata().getActivate() );
+ activateMethod = getMethod( implementationObject, getComponentMetadata().getActivate(),
+ ReflectionHelper.ACTIVATE_ACCEPTED_PARAMETERS );
}
// 4. Call the activate method, if present
- if ( activateMethod != null && !invokeMethod( activateMethod, implementationObject, componentContext ) )
+ if ( activateMethod != null && !invokeMethod( activateMethod, implementationObject, componentContext, -1 ) )
{
// 112.5.8 If the activate method throws an exception, SCR must log an error message
// containing the exception with the Log Service and activation fails
@@ -252,20 +219,25 @@
}
- protected void disposeImplementationObject( Object implementationObject, ComponentContext componentContext )
+ protected void disposeImplementationObject( Object implementationObject, ComponentContext componentContext,
+ int reason )
{
// get the method
if ( deactivateMethod == ReflectionHelper.SENTINEL )
{
- deactivateMethod = getMethod( implementationObject, getComponentMetadata().getDeactivate() );
+ deactivateMethod = getMethod( implementationObject, getComponentMetadata().getDeactivate(),
+ ReflectionHelper.DEACTIVATE_ACCEPTED_PARAMETERS );
}
// 1. Call the deactivate method, if present
// don't care for the result, the error (acccording to 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) has already been logged
- invokeMethod( deactivateMethod, implementationObject, componentContext );
+ if ( deactivateMethod != null )
+ {
+ invokeMethod( deactivateMethod, implementationObject, componentContext, reason );
+ }
// 2. Unbind any bound services
Iterator it = getDependencyManagers();
@@ -386,7 +358,9 @@
{
log( LogService.LOG_DEBUG, "Deactivating and Activating to reconfigure from configuration",
getComponentMetadata(), null );
- reactivate();
+ int reason = ( configuration == null ) ? ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED
+ : ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED;
+ reactivate( reason );
}
}
@@ -399,13 +373,16 @@
* @param implementationObject The object whose class (and its super classes)
* may provide the method
* @param methodName Name of the method to look for
+ * @param methodTester The {@link ReflectionHelper.MethodTester} instance
+ * used to select the actual method.
* @return The named method or <code>null</code> if no such method is available.
*/
- private Method getMethod( final Object implementationObject, final String methodName )
+ private Method getMethod( final Object implementationObject, final String methodName,
+ final ReflectionHelper.MethodTester methodTester )
{
try
{
- return ReflectionHelper.getMethod( implementationObject.getClass(), methodName, ACTIVATE_PARAMETER_LIST );
+ return ReflectionHelper.getMethod( implementationObject.getClass(), methodName, methodTester );
}
catch ( InvocationTargetException ite )
{
@@ -434,6 +411,10 @@
* @param implementationObject The object on which to call the method.
* @param componentContext The <code>ComponentContext</code> used to
* build the argument list
+ * @param reason The deactivation reason code. This should be one of the
+ * values in the {@link ComponentConstants} interface. This parameter
+ * is only of practical use for calling deactivate methods, which may
+ * take a numeric argument indicating the deactivation reason.
*
* @return <code>true</code> if the method should be considered invoked
* successfully. <code>false</code> is returned if the method threw
@@ -442,7 +423,7 @@
* @throws NullPointerException if any of the parameters is <code>null</code>.
*/
private boolean invokeMethod( final Method method, final Object implementationObject,
- final ComponentContext componentContext )
+ final ComponentContext componentContext, int reason )
{
final String methodName = method.getName();
try
@@ -452,23 +433,26 @@
Object[] param = new Object[paramTypes.length];
for ( int i = 0; i < param.length; i++ )
{
- if ( paramTypes[i] == COMPONENT_CONTEXT_CLASS )
+ if ( paramTypes[i] == ReflectionHelper.COMPONENT_CONTEXT_CLASS )
{
param[i] = componentContext;
}
- else if ( paramTypes[i] == BUNDLE_CONTEXT_CLASS )
+ else if ( paramTypes[i] == ReflectionHelper.BUNDLE_CONTEXT_CLASS )
{
param[i] = componentContext.getBundleContext();
}
- else if ( paramTypes[i] == MAP_CLASS )
+ else if ( paramTypes[i] == ReflectionHelper.MAP_CLASS )
{
// note: getProperties() returns a Hashtable which is a Map
param[i] = componentContext.getProperties();
}
+ else if ( paramTypes[i] == ReflectionHelper.INTEGER_CLASS || paramTypes[i] == Integer.TYPE)
+ {
+ param[i] = new Integer(reason);
+ }
}
- method.invoke( implementationObject, new Object[]
- { componentContext } );
+ method.invoke( implementationObject, param );
}
catch ( IllegalAccessException ex )
{
@@ -485,6 +469,14 @@
// method threw, so it was a failure
return false;
}
+ catch ( Throwable t )
+ {
+ // anything else went wrong, log the message and fail the invocation
+ log( LogService.LOG_ERROR, "The " + methodName + " method could not be called", getComponentMetadata(), t );
+
+ // method invocation threw, so it was a failure
+ return false;
+ }
// assume success (also if the method is not available or accessible)
return true;
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ReflectionHelper.java b/scr/src/main/java/org/apache/felix/scr/impl/ReflectionHelper.java
index 2c33f52..5f31c1b 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ReflectionHelper.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ReflectionHelper.java
@@ -22,6 +22,13 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
/**
@@ -31,8 +38,24 @@
final class ReflectionHelper
{
+ // Method instance to implement tristate behaviour on method fields:
+ // unchecked (SENTINEL), no method (null), valid method (method object)
static final Method SENTINEL;
+ // class references to simplify parameter checking
+ static final Class COMPONENT_CONTEXT_CLASS = ComponentContext.class;
+ static final Class BUNDLE_CONTEXT_CLASS = BundleContext.class;
+ static final Class MAP_CLASS = Map.class;
+ static final Class INTEGER_CLASS = Integer.class;
+
+ // Helper used to find the best matching activate and modified methods
+ static final ActivatorMethodTester ACTIVATE_ACCEPTED_PARAMETERS = new ActivatorMethodTester( new Class[]
+ { COMPONENT_CONTEXT_CLASS, BUNDLE_CONTEXT_CLASS, MAP_CLASS } );
+
+ // Helper used to find the best matching deactivate method
+ static final ActivatorMethodTester DEACTIVATE_ACCEPTED_PARAMETERS = new ActivatorMethodTester( new Class[]
+ { COMPONENT_CONTEXT_CLASS, BUNDLE_CONTEXT_CLASS, MAP_CLASS, Integer.TYPE, INTEGER_CLASS } );
+
static
{
Method tmpSentinel = null;
@@ -78,26 +101,62 @@
* @throws InvocationTargetException If an unexpected Throwable is caught
* trying to access the desired method.
*/
- static Method getMethod( final Class objectClass, final String name, final Class[][] parameterTypesList )
+ static Method getMethod( final Class objectClass, final String name, final MethodTester tester )
throws NoSuchMethodException, InvocationTargetException
{
// whether we accept package private methods
boolean acceptPackage = true;
- String packageName = getPackageName( objectClass );
+ final String packageName = getPackageName( objectClass );
+ final Class[] parameterTypesList = tester.getParameterLists();
for ( Class clazz = objectClass; clazz != null; clazz = clazz.getSuperclass() )
{
// turns false on first package not equal to the package of objectClass
acceptPackage &= packageName.equals( getPackageName( clazz ) );
+ final boolean acceptPrivate = clazz == objectClass;
+ // check parameter types first
for ( int i = 0; i < parameterTypesList.length; i++ )
{
- Class[] parameterTypes = parameterTypesList[i];
+ Class[] parameterTypes = new Class[]
+ { parameterTypesList[i] };
try
{
// find the declared method in this class
- return getMethod( clazz, name, parameterTypes, clazz == objectClass, acceptPackage );
+ return getMethod( clazz, name, parameterTypes, acceptPrivate, acceptPackage );
+ }
+ catch ( NoSuchMethodException nsme )
+ {
+ // ignore for now
+ }
+ catch ( Throwable throwable )
+ {
+ // unexpected problem accessing the method, don't let everything
+ // blow up in this situation, just throw a declared exception
+ throw new InvocationTargetException( throwable, "Unexpected problem trying to get method " + name );
+ }
+ }
+
+ // check methods with MethodTester
+ Method[] methods = clazz.getDeclaredMethods();
+ for ( int i = 0; i < methods.length; i++ )
+ {
+ if ( methods[i].getName().equals( name ) && tester.isSuitable( methods[i] )
+ && accept( methods[i], acceptPrivate, acceptPackage ) )
+ {
+ // check modifiers etc.
+ return methods[i];
+ }
+ }
+
+ // finally check method with no arguments
+ if ( tester.acceptEmpty() )
+ {
+ try
+ {
+ // find the declared method in this class
+ return getMethod( clazz, name, null, clazz == objectClass, acceptPackage );
}
catch ( NoSuchMethodException nsme )
{
@@ -148,7 +207,6 @@
// accept public and protected methods only and ensure accessibility
if ( accept( method, acceptPrivate, acceptPackage ) )
{
- method.setAccessible( true );
return method;
}
}
@@ -172,7 +230,8 @@
/**
* Returns <code>true</code> if the method is acceptable to be returned from the
- * {@link #getMethod(Class, String, Class[], boolean, boolean)}.
+ * {@link #getMethod(Class, String, Class[], boolean, boolean)} and also
+ * makes the method accessible.
* <p>
* This method returns <code>true</code> iff:
* <ul>
@@ -211,18 +270,26 @@
// accept public and protected methods
if ( Modifier.isPublic( mod ) || Modifier.isProtected( mod ) )
{
+ method.setAccessible( true );
return true;
}
// accept private if accepted
if ( Modifier.isPrivate( mod ) )
{
- return acceptPrivate;
+ if ( acceptPrivate )
+ {
+ method.setAccessible( acceptPrivate );
+ return true;
+ }
+
+ return false;
}
// accept default (package)
if ( acceptPackage )
{
+ method.setAccessible( true );
return true;
}
@@ -241,4 +308,80 @@
int dot = name.lastIndexOf( '.' );
return ( dot > 0 ) ? name.substring( 0, dot ) : "";
}
+
+ //---------- inner classes
+
+ static interface MethodTester
+ {
+
+ /**
+ * Returns <code>true</code> if methods without arguments are acceptable.
+ */
+ boolean acceptEmpty();
+
+
+ /**
+ * Returns <code>true</code> if the method <code>m</code> is suitable for
+ * this tester.
+ */
+ boolean isSuitable( Method m );
+
+
+ /**
+ * Returns an array of parameters which are acceptable as single parameter
+ * arguments to methods.
+ */
+ Class[] getParameterLists();
+ }
+
+ static final class ActivatorMethodTester implements ReflectionHelper.MethodTester
+ {
+ private final Class[] parameterLists;
+ private final Set methods;
+
+
+ ActivatorMethodTester( Class[] acceptedParameters )
+ {
+ parameterLists = acceptedParameters;
+ methods = new HashSet();
+ methods.addAll( Arrays.asList( acceptedParameters ) );
+ }
+
+
+ public boolean acceptEmpty()
+ {
+ return true;
+ }
+
+
+ public boolean isSuitable( Method m )
+ {
+ Class[] types = m.getParameterTypes();
+
+ // require two or more arguments
+ if ( types.length < 2 )
+ {
+ return false;
+ }
+
+ // check for argument types
+ for ( int i = 0; i < types.length; i++ )
+ {
+ if ( !methods.contains( types[i] ) )
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ public Class[] getParameterLists()
+ {
+ return parameterLists;
+ }
+
+ }
+
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ServiceFactoryComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/ServiceFactoryComponentManager.java
index 02e3fb7..60204d7 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ServiceFactoryComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ServiceFactoryComponentManager.java
@@ -1,4 +1,4 @@
-/*
+/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
@@ -24,6 +24,7 @@
import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.ComponentInstance;
import org.osgi.service.log.LogService;
@@ -135,21 +136,21 @@
// private ComponentContext and implementation instances
ComponentContext serviceContext = ( ComponentContext ) serviceContexts.remove( service );
- disposeImplementationObject( service, serviceContext );
+ disposeImplementationObject( service, serviceContext, ComponentConstants.DEACTIVATION_REASON_DISPOSED );
// if this was the last use of the component, go back to REGISTERED state
if ( serviceContexts.isEmpty() )
{
- if (getState() == STATE_ACTIVE)
- {
- synchronized(this)
- {
- if (getState() == STATE_ACTIVE)
- {
- changeState(Registered.getInstance());
- }
- }
- }
+ if ( getState() == STATE_ACTIVE )
+ {
+ synchronized ( this )
+ {
+ if ( getState() == STATE_ACTIVE )
+ {
+ changeState( Registered.getInstance() );
+ }
+ }
+ }
}
}
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/ReflectionHelperTest.java b/scr/src/test/java/org/apache/felix/scr/impl/ReflectionHelperTest.java
index dc5c052..7f88f6e 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/ReflectionHelperTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/ReflectionHelperTest.java
@@ -197,7 +197,7 @@
IllegalAccessException
{
Method method = ReflectionHelper.getMethod( obj.getClass(), methodName,
- ImmediateComponentManager.ACTIVATE_PARAMETER_LIST );
+ ReflectionHelper.ACTIVATE_ACCEPTED_PARAMETERS );
try
{
method.invoke( obj, new Object[method.getParameterTypes().length] );