FELIX-1440 Add support for method lookup termination on suitable
non-accessible methods for activate/deactivate methods plus the
respective test case
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@800267 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/ReflectionHelper.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/ReflectionHelper.java
index f0c5c38..9bdf532 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/ReflectionHelper.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/ReflectionHelper.java
@@ -114,13 +114,19 @@
final String packageName = getPackageName( objectClass );
final Class[] parameterTypesList = tester.getParameterLists();
- for ( Class clazz = objectClass; clazz != null; clazz = clazz.getSuperclass() )
+ // flag indicating a suitable but inaccessible method has been found
+ boolean suitableMethodNotAccessible = false;
+
+ // lookup methods until there is no more super class or a class would
+ // have at least one suitable method but none is accessible
+ for ( Class clazz = objectClass; clazz != null && !suitableMethodNotAccessible; clazz = clazz.getSuperclass() )
{
// turns false on first package not equal to the package of objectClass (or different class loader)
acceptPackage &= packageName.equals( getPackageName( clazz ) )
&& clazz.getClassLoader() == objectClass.getClassLoader();
final boolean acceptPrivate = tester.acceptPrivate() && clazz == objectClass;
+
// check parameter types first
for ( int i = 0; i < parameterTypesList.length; i++ )
{
@@ -136,6 +142,10 @@
{
// ignore for now
}
+ catch ( SuitableMethodNotAccessibleException smnae )
+ {
+ suitableMethodNotAccessible = true;
+ }
catch ( Throwable throwable )
{
// unexpected problem accessing the method, don't let everything
@@ -148,11 +158,16 @@
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 ) )
+ if ( methods[i].getName().equals( name ) && tester.isSuitable( methods[i] ) )
{
- // check modifiers etc.
- return methods[i];
+ if ( accept( methods[i], acceptPrivate, acceptPackage ) )
+ {
+ // check modifiers etc.
+ return methods[i];
+ }
+
+ // method is suitable but not accessible, flag it
+ suitableMethodNotAccessible = true;
}
}
@@ -168,6 +183,10 @@
{
// ignore for now
}
+ catch ( SuitableMethodNotAccessibleException smnae )
+ {
+ suitableMethodNotAccessible = true;
+ }
catch ( Throwable throwable )
{
// unexpected problem accessing the method, don't let everything
@@ -199,11 +218,15 @@
*
* @throws NoSuchMethodException If no public or protected method with
* the given name can be found in the class or any of its super classes.
+ * @throws SuitableMethodNotAccessibleException If method with the given
+ * name taking the parameters is found in the class but the method
+ * is not accessible.
* @throws InvocationTargetException If an unexpected Throwable is caught
* trying to access the desired method.
*/
public static Method getMethod( Class clazz, String name, Class[] parameterTypes, boolean acceptPrivate,
- boolean acceptPackage ) throws NoSuchMethodException, InvocationTargetException
+ boolean acceptPackage ) throws NoSuchMethodException, SuitableMethodNotAccessibleException,
+ InvocationTargetException
{
try
{
@@ -228,9 +251,8 @@
throw new InvocationTargetException( throwable, "Unexpected problem trying to get method " + name );
}
- // walked up the complete super class hierarchy and still not found
- // anything, sigh ...
- throw new NoSuchMethodException( name );
+ // suitable method found which is not accessible
+ throw new SuitableMethodNotAccessibleException();
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/SuitableMethodNotAccessibleException.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/SuitableMethodNotAccessibleException.java
new file mode 100644
index 0000000..d5dedd6
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/SuitableMethodNotAccessibleException.java
@@ -0,0 +1,24 @@
+/*
+ * 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
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr.impl.helper;
+
+
+public class SuitableMethodNotAccessibleException extends Exception
+{
+}
\ No newline at end of file
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/BindMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/BindMethod.java
index 524ffc3..384d101 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/BindMethod.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/BindMethod.java
@@ -23,6 +23,7 @@
import java.lang.reflect.Method;
import org.apache.felix.scr.impl.helper.ReadOnlyDictionary;
import org.apache.felix.scr.impl.helper.ReflectionHelper;
+import org.apache.felix.scr.impl.helper.SuitableMethodNotAccessibleException;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
@@ -80,24 +81,33 @@
* can be found in the target class or any super class.
* @throws InvocationTargetException If an unexpected Throwable is caught
* trying to find the requested method.
- * @throws SuitableMethodNotAccessibleException If a suitable method was
- * found which is not accessible
*/
private Method findMethod( final Class targetClass, final boolean acceptPrivate, final boolean acceptPackage )
- throws InvocationTargetException//, SuitableMethodNotAccessibleException
+ throws InvocationTargetException
{
// 112.3.1 The method is searched for using the following priority
- // 1. The method's parameter type is org.osgi.framework.ServiceReference
- // 2. The method's parameter type is the type specified by the
- // reference's interface attribute
- // 3. The method's parameter type is assignable from the type specified
- // by the reference's interface attribute
+ // 1 - Service reference parameter
+ // 2 - Service object parameter
+ // 3 - Service interface assignement compatible methods
+ // 4 - same as 2, but with Map param (DS 1.1 only)
+ // 5 - same as 3, but with Map param (DS 1.1 only)
+
+ // flag indicating a suitable but inaccessible method has been found
+ boolean suitableMethodNotAccessible = false;
// Case 1 - Service reference parameter
- Method method = getServiceReferenceMethod( targetClass, acceptPrivate, acceptPackage );
- if ( method != null )
+ Method method;
+ try
{
- return method;
+ method = getServiceReferenceMethod( targetClass, acceptPrivate, acceptPackage );
+ if ( method != null )
+ {
+ return method;
+ }
+ }
+ catch ( SuitableMethodNotAccessibleException ex )
+ {
+ suitableMethodNotAccessible = true;
}
// for further methods we need the class of the service object
@@ -105,15 +115,21 @@
if ( parameterClass != null )
{
- // Case2 - Service object parameter
- method = getServiceObjectMethod( targetClass, parameterClass, acceptPrivate, acceptPackage );
- if ( method != null )
+ // Case 2 - Service object parameter
+ try
{
- return method;
+ method = getServiceObjectMethod( targetClass, parameterClass, acceptPrivate, acceptPackage );
+ if ( method != null )
+ {
+ return method;
+ }
+ }
+ catch ( SuitableMethodNotAccessibleException ex )
+ {
+ suitableMethodNotAccessible = true;
}
// Case 3 - Service interface assignement compatible methods
- SuitableMethodNotAccessibleException methodAccessibleEx = null;
try
{
method = getServiceObjectAssignableMethod( targetClass, parameterClass, acceptPrivate, acceptPackage );
@@ -124,21 +140,28 @@
}
catch ( SuitableMethodNotAccessibleException ex )
{
- methodAccessibleEx = ex;
+ suitableMethodNotAccessible = true;
}
// signatures taking a map are only supported starting with DS 1.1
if ( m_isDS11 )
{
- // Case 4: same as case 2, but + Map param (DS 1.1 only)
- method = getServiceObjectWithMapMethod( targetClass, parameterClass, acceptPrivate, acceptPackage );
- if ( method != null )
+ // Case 4 - same as case 2, but + Map param (DS 1.1 only)
+ try
{
- return method;
+ method = getServiceObjectWithMapMethod( targetClass, parameterClass, acceptPrivate, acceptPackage );
+ if ( method != null )
+ {
+ return method;
+ }
+ }
+ catch ( SuitableMethodNotAccessibleException ex )
+ {
+ suitableMethodNotAccessible = true;
}
- // Case 5: same as case 3, but + Map param (DS 1.1 only)
+ // Case 5 - same as case 3, but + Map param (DS 1.1 only)
try
{
method = getServiceObjectAssignableWithMapMethod( targetClass, parameterClass, acceptPrivate,
@@ -150,20 +173,20 @@
}
catch ( SuitableMethodNotAccessibleException ex )
{
- methodAccessibleEx = ex;
+ suitableMethodNotAccessible = true;
}
}
- // if at least one suitable method could be found but none of
- // the suitable methods are accessible, we have to terminate
- if ( methodAccessibleEx != null )
- {
- m_logger.log( LogService.LOG_ERROR,
- "DependencyManager : Suitable but non-accessible method found in class " + targetClass.getName() );
- return null;
- }
+ }
+ // if at least one suitable method could be found but none of
+ // the suitable methods are accessible, we have to terminate
+ if (suitableMethodNotAccessible )
+ {
+ m_logger.log( LogService.LOG_ERROR,
+ "DependencyManager : Suitable but non-accessible method found in class " + targetClass.getName() );
+ return null;
}
// if we get here, we have no method, so check the super class
@@ -231,11 +254,13 @@
* be considered.
* @return The requested method or <code>null</code> if no acceptable method
* can be found in the target class.
+ * @throws SuitableMethodNotAccessibleException If a suitable method was
+ * found which is not accessible
* @throws InvocationTargetException If an unexpected Throwable is caught
* trying to find the requested method.
*/
private Method getServiceReferenceMethod( final Class targetClass, boolean acceptPrivate, boolean acceptPackage )
- throws InvocationTargetException
+ throws SuitableMethodNotAccessibleException, InvocationTargetException
{
try
{
@@ -264,11 +289,13 @@
* be considered.
* @return The requested method or <code>null</code> if no acceptable method
* can be found in the target class.
+ * @throws SuitableMethodNotAccessibleException If a suitable method was
+ * found which is not accessible
* @throws InvocationTargetException If an unexpected Throwable is caught
* trying to find the requested method.
*/
private Method getServiceObjectMethod( final Class targetClass, final Class parameterClass, boolean acceptPrivate,
- boolean acceptPackage ) throws InvocationTargetException
+ boolean acceptPackage ) throws SuitableMethodNotAccessibleException, InvocationTargetException
{
try
{
@@ -366,11 +393,14 @@
* be considered.
* @return The requested method or <code>null</code> if no acceptable method
* can be found in the target class.
+ * @throws SuitableMethodNotAccessibleException If a suitable method was
+ * found which is not accessible
* @throws InvocationTargetException If an unexpected Throwable is caught
* trying to find the requested method.
*/
private Method getServiceObjectWithMapMethod( final Class targetClass, final Class parameterClass,
- boolean acceptPrivate, boolean acceptPackage ) throws InvocationTargetException
+ boolean acceptPrivate, boolean acceptPackage ) throws SuitableMethodNotAccessibleException,
+ InvocationTargetException
{
try
{
@@ -603,10 +633,4 @@
}
- //---------- Logger ------------------------------------
-
- static class SuitableMethodNotAccessibleException extends Exception
- {
- }
-
}
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/helper/ReflectionHelperTest.java b/scr/src/test/java/org/apache/felix/scr/impl/helper/ReflectionHelperTest.java
index 5b22b5e..e9212b5 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/helper/ReflectionHelperTest.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/helper/ReflectionHelperTest.java
@@ -184,6 +184,27 @@
}
+ public void test_suitable_method_selection() throws Exception
+ {
+ // this would be the protected BaseObject.activate_suitable
+ checkMethod( base, "activate_suitable" );
+ checkMethod( level1, "activate_suitable" );
+
+ // this would be the private Level2Object.activate_suitable
+ checkMethod( level2, "activate_suitable" );
+
+ // this must fail to find a method, since Level2Object's activate_suitable
+ // is private and terminates the search for Level3Object
+ try {
+ checkMethod( level3, "activate_suitable" );
+ fail("Level3Object must not find activate_suitable method");
+ } catch (NoSuchMethodException nsme) {
+ // expecting method lookup abort on suitable private
+ // method in Level2Object class
+ }
+ }
+
+
//---------- internal
/**
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/BaseObject.java b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/BaseObject.java
index 08ad1c7..59fd9fa 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/BaseObject.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances/BaseObject.java
@@ -47,4 +47,10 @@
{
throw new MethodNameException( "activate_comp_bundle" );
}
+
+
+ protected void activate_suitable( ComponentContext ctx )
+ {
+ throw new MethodNameException( "activate_suitable" );
+ }
}
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances2/Level2Object.java b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances2/Level2Object.java
index 0e4c8e0..510f941 100644
--- a/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances2/Level2Object.java
+++ b/scr/src/test/java/org/apache/felix/scr/impl/metadata/instances2/Level2Object.java
@@ -31,7 +31,7 @@
private void activate_comp_map( ComponentContext ctx, Map map )
{
- throw new MethodNameException("activate_comp_map");
+ throw new MethodNameException( "activate_comp_map" );
}
@@ -39,12 +39,18 @@
// Map has higher precedence
public void activate_collision()
{
- throw new MethodNameException("not_expected_to_be_found");
+ throw new MethodNameException( "not_expected_to_be_found" );
}
public void activate_collision( Map map )
{
- throw new MethodNameException("activate_collision");
+ throw new MethodNameException( "activate_collision" );
+ }
+
+
+ private void activate_suitable( Map map )
+ {
+ throw new MethodNameException( "activate_suitable" );
}
}