FELIX-927 Apply patch by Alin Dreghiciu to allow for better bind/unbind
method signatures (thanks for the patch)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@798554 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 745bb09..d92528f 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
@@ -28,6 +28,7 @@
import java.util.Set;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
@@ -45,6 +46,7 @@
// class references to simplify parameter checking
public static final Class COMPONENT_CONTEXT_CLASS = ComponentContext.class;
public static final Class BUNDLE_CONTEXT_CLASS = BundleContext.class;
+ public static final Class SERVICE_REFERENCE_CLASS = ServiceReference.class;
public static final Class MAP_CLASS = Map.class;
public static final Class INTEGER_CLASS = Integer.class;
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
new file mode 100644
index 0000000..9ecbb27
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/BindMethod.java
@@ -0,0 +1,361 @@
+/*
+ * 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.manager;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.felix.scr.impl.helper.ReflectionHelper;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+
+/**
+ * Component method to be invoked on service (un)binding.
+ */
+class BindMethod
+{
+
+ private final String m_methodName;
+ private final Class m_componentClass;
+ private final String m_referenceName;
+ private final String m_referenceClassName;
+ private final Logger m_logger;
+
+ private Method m_method = null;
+ private State m_state;
+
+
+ BindMethod( final String methodName, final Class componentClass, final String referenceName,
+ final String referenceClassName, final Logger logger )
+ {
+ m_methodName = methodName;
+ m_componentClass = componentClass;
+ m_referenceName = referenceName;
+ m_referenceClassName = referenceClassName;
+ m_logger = logger;
+ if ( m_methodName == null )
+ {
+ m_state = new NotApplicable();
+ }
+ else
+ {
+ m_state = new NotResolved();
+ }
+ }
+
+
+ private Method findMethod( final Class targetClass ) throws InvocationTargetException
+ {
+ Class parameterClass = null;
+
+ // 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
+ try
+ {
+ // Case 1 - ServiceReference parameter
+ return ReflectionHelper.getMethod( targetClass, m_methodName, new Class[]
+ { ReflectionHelper.SERVICE_REFERENCE_CLASS }, false, // do not accept private methods
+ false // do not accept package methods
+ );
+ }
+ catch ( NoSuchMethodException ex )
+ {
+
+ try
+ {
+ // Case2 - Service object parameter
+
+ // need the class loader of the target class, which may be the
+ // system classloader, which case getClassLoader may retur null
+ ClassLoader loader = targetClass.getClassLoader();
+ if ( loader == null )
+ {
+ loader = ClassLoader.getSystemClassLoader();
+ }
+
+ parameterClass = loader.loadClass( m_referenceClassName );
+ return ReflectionHelper.getMethod( targetClass, m_methodName, new Class[]
+ { parameterClass }, false, false );
+ }
+ catch ( NoSuchMethodException ex2 )
+ {
+
+ // Case 3 - Service interface assignement compatible methods
+
+ // Get all potential bind methods
+ Method candidateBindMethods[] = targetClass.getDeclaredMethods();
+
+ // Iterate over them
+ for ( int i = 0; i < candidateBindMethods.length; i++ )
+ {
+ Method method = candidateBindMethods[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( m_methodName ) )
+ {
+
+ // Get the parameter type
+ Class theParameter = parameters[0];
+
+ // Check if the parameter type is ServiceReference
+ // or 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() ) )
+ {
+ if ( !method.isAccessible() )
+ {
+ method.setAccessible( true );
+ }
+ return method;
+ }
+ }
+ }
+ }
+
+ // Case 4: same as case 2, but + Map param
+ try
+ {
+ // need the class loader of the target class, which may be the
+ // system classloader, which case getClassLoader may retur null
+ ClassLoader loader = targetClass.getClassLoader();
+ if ( loader == null )
+ {
+ loader = ClassLoader.getSystemClassLoader();
+ }
+
+ parameterClass = loader.loadClass( m_referenceClassName );
+ return ReflectionHelper.getMethod( targetClass, m_methodName, new Class[]
+ { parameterClass, Map.class }, false, false );
+ }
+ catch ( NoSuchMethodException ex3 )
+ {
+
+ }
+ catch ( ClassNotFoundException ex3 )
+ {
+ // if we can't load the class, perhaps the method is declared in a super class
+ // so we try this class next
+ }
+ }
+ catch ( ClassNotFoundException ex2 )
+ {
+ // if we can't load the class, perhaps the method is declared in a super class
+ // so we try this class next
+ }
+
+ // TODO: Case 5: same as case 3, but + Map param
+ }
+
+ // if we get here, we have no method, so check the super class
+ Class superClass = targetClass.getSuperclass();
+ return ( superClass != null ) ? findMethod( superClass ) : null;
+ }
+
+
+ private boolean invokeMethod( final Object componentInstance, final Service service )
+ {
+ final Class[] paramTypes = m_method.getParameterTypes();
+ final Object[] params = new Object[paramTypes.length];
+ Map properties = null;
+ for ( int i = 0; i < params.length; i++ )
+ {
+ if ( paramTypes[i] == ReflectionHelper.SERVICE_REFERENCE_CLASS )
+ {
+ params[i] = service.getReference();
+ }
+ else if ( paramTypes[i] == ReflectionHelper.MAP_CLASS )
+ {
+ if ( properties == null )
+ {
+ final ServiceReference serviceReference = service.getReference();
+ properties = new HashMap();
+ final String[] keys = serviceReference.getPropertyKeys();
+ if ( keys != null )
+ {
+ for ( int j = 0; j < keys.length; j++ )
+ {
+ final String key = keys[j];
+ properties.put( key, serviceReference.getProperty( key ) );
+ }
+ }
+ }
+ params[i] = properties;
+ }
+ else
+ {
+ params[i] = service.getInstance();
+ if ( params[i] == null )
+ {
+ m_logger.log( LogService.LOG_INFO, "Dependency Manager: Service " + service.getReference()
+ + " has already gone, not " + getMethodNamePrefix() + "binding" );
+ return false;
+ }
+ }
+ }
+ try
+ {
+ m_method.invoke( componentInstance, params );
+ m_logger.log( LogService.LOG_DEBUG, getMethodNamePrefix() + "bound: " + m_referenceName + "/"
+ + service.getReference().getProperty( Constants.SERVICE_ID ) );
+ }
+ 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
+ m_logger.log( LogService.LOG_ERROR, getMethodNamePrefix() + "bind method " + m_methodName + "] cannot be called",
+ ex );
+ }
+ catch ( InvocationTargetException ex )
+ {
+ // 112.5.7 If a bind method throws an exception, SCR must log an
+ // error message containing the exception [...]
+ m_logger.log( LogService.LOG_ERROR, "DependencyManager : exception while invoking " + m_methodName + "()",
+ ex.getCause() );
+ }
+ return true;
+ }
+
+
+ protected String getMethodNamePrefix()
+ {
+ return "";
+ }
+
+
+ //---------- State management ------------------------------------
+
+ boolean invoke( final Object componentInstance, final Service service )
+ {
+ return m_state.invoke( componentInstance, service );
+ }
+
+ private static interface State
+ {
+
+ boolean invoke( final Object componentInstance, final Service service );
+ }
+
+ private static class NotApplicable implements State
+ {
+
+ public boolean invoke( final Object componentInstance, final Service service )
+ {
+ return true;
+ }
+ }
+
+ private class NotResolved implements State
+ {
+
+ public boolean invoke( final Object componentInstance, final Service service )
+ {
+ m_logger.log( LogService.LOG_DEBUG, "getting " + getMethodNamePrefix() + "bind: " + m_methodName );
+ try
+ {
+ m_method = findMethod( m_componentClass );
+ if ( m_method == null )
+ {
+ m_state = new NotFound();
+ }
+ else
+ {
+ m_state = new Resolved();
+ }
+ return m_state.invoke( componentInstance, service );
+ }
+ catch ( InvocationTargetException ex )
+ {
+ m_state = new NotFound();
+ // 112.5.7 If a bind method throws an exception, SCR must log an
+ // error message containing the exception [...]
+ m_logger.log( LogService.LOG_ERROR, "DependencyManager : exception while finding " + m_methodName
+ + "()", ex.getCause() );
+ }
+ return true;
+ }
+ }
+
+ private class NotFound implements State
+ {
+
+ public boolean invoke( final Object componentInstance, final Service service )
+ {
+ // 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_logger.log( LogService.LOG_ERROR, getMethodNamePrefix() + "bind method [" + m_methodName + "] not found" );
+ return true;
+ }
+ }
+
+ private class Resolved implements State
+ {
+
+ public boolean invoke( final Object componentInstance, final Service service )
+ {
+ m_logger.log( LogService.LOG_DEBUG, "invoking " + getMethodNamePrefix() + "bind: " + m_methodName );
+ return invokeMethod( componentInstance, service );
+ }
+ }
+
+ //---------- Service abstraction ------------------------------------
+
+ static interface Service
+ {
+
+ ServiceReference getReference();
+
+
+ Object getInstance();
+
+ }
+
+ //---------- Logger ------------------------------------
+
+ static interface Logger
+ {
+
+ void log( int level, String message );
+
+
+ void log( int level, String message, Throwable ex );
+
+ }
+
+}
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 a889f12..1cea987 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
@@ -77,13 +77,13 @@
private transient Object m_componentInstance;
// the bind method
- private Method m_bind;
+ private BindMethod m_bind;
// whether the bind method takes a service reference
private boolean m_bindUsesReference;
// the unbind method
- private Method m_unbind;
+ private UnbindMethod m_unbind;
// whether the unbind method takes a service reference
private boolean m_unbindUsesReference;
@@ -114,6 +114,39 @@
.getComponentMetadata(), null );
}
+ /**
+ * Initialize binding methods.
+ */
+ private void initBindingMethods()
+ {
+ BindMethod.Logger logger = new BindMethod.Logger()
+ {
+
+ public void log( int level, String message )
+ {
+ log( level, message, null );
+ }
+
+ public void log( int level, String message, Throwable ex )
+ {
+ m_componentManager.log( level, message, m_componentManager.getComponentMetadata(), ex );
+ }
+ };
+ m_bind = new BindMethod( m_dependencyMetadata.getBind(),
+ m_componentInstance.getClass(),
+ m_dependencyMetadata.getName(),
+ m_dependencyMetadata.getInterface(),
+ logger
+ );
+ m_unbind = new UnbindMethod( m_dependencyMetadata.getUnbind(),
+ m_componentInstance.getClass(),
+ m_dependencyMetadata.getName(),
+ m_dependencyMetadata.getInterface(),
+ logger
+ );
+ }
+
+
//---------- ServiceListener interface ------------------------------------
@@ -486,10 +519,6 @@
ungetService( boundRefs[i] );
}
}
-
- // drop the method references (to help GC)
- m_bind = null;
- m_unbind = null;
}
@@ -855,6 +884,7 @@
boolean open( Object instance )
{
m_componentInstance = instance;
+ initBindingMethods();
return bind();
}
@@ -872,6 +902,9 @@
finally
{
m_componentInstance = null;
+ m_bind = null;
+ m_unbind = null;
+
}
}
@@ -969,120 +1002,6 @@
}
}
-
- /**
- * Gets a bind or unbind method according to the policies described in the
- * specification
- *
- * @param methodname The name of the method
- * @param targetClass the class to which the method belongs to
- * @param parameterClassName the name of the class of the parameter that is
- * passed to the method
- * @param serviceBundle the bundle of the registered service.
- * @return the method or null
- * @throws ClassNotFoundException if the class for parameterClassName cannot
- * be found.
- * @throws InvocationTargetException If an unexpected error occurrs trying
- * to get the method from the targetClass.
- */
- private Method getBindingMethod( String methodname, Class targetClass, String parameterClassName )
- throws InvocationTargetException
- {
- Class parameterClass = null;
-
- // 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
- try
- {
- // Case 1 - ServiceReference parameter
- return ReflectionHelper.getMethod( targetClass, methodname, new Class[]
- { SERVICE_REFERENCE_CLASS }, false, false );
- }
- catch ( NoSuchMethodException ex )
- {
-
- try
- {
- // Case2 - Service object parameter
-
- // need the class loader of the target class, which may be the
- // system classloader, which case getClassLoader may retur null
- ClassLoader loader = targetClass.getClassLoader();
- if ( loader == null )
- {
- loader = ClassLoader.getSystemClassLoader();
- }
-
- parameterClass = loader.loadClass( parameterClassName );
- return ReflectionHelper.getMethod( targetClass, methodname, new Class[]
- { parameterClass }, false, false );
- }
- catch ( NoSuchMethodException ex2 )
- {
-
- // Case 3 - Service interface assignement compatible methods
-
- // Get all potential bind methods
- Method candidateBindMethods[] = targetClass.getDeclaredMethods();
-
- // Iterate over them
- for ( int i = 0; i < candidateBindMethods.length; i++ )
- {
- Method method = candidateBindMethods[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 ) )
- {
-
- // Get the parameter type
- Class theParameter = parameters[0];
-
- // Check if the parameter type is ServiceReference
- // or 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() ) )
- {
- if ( !method.isAccessible() )
- {
- method.setAccessible( true );
- }
- return method;
- }
- }
- }
- }
- }
- catch ( ClassNotFoundException ex2 )
- {
- // if we can't load the class, perhaps the method is declared in a super class
- // so we try this class next
- }
-
-
- // TODO: Case 4: same as case 2, but + Map param
- // TODO: Case 5: same as case 3, but + Map param
- }
-
- // if we get here, we have no method, so check the super class
- targetClass = targetClass.getSuperclass();
- return ( targetClass != null ) ? getBindingMethod( methodname, targetClass, parameterClassName ) : null;
- }
-
-
/**
* Calls 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
@@ -1099,86 +1018,30 @@
* be handed over to the bind method but the service cannot be
* retrieved using the service reference.
*/
- private boolean invokeBindMethod( ServiceReference ref )
+ private boolean invokeBindMethod( final 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_componentInstance != null )
+ if( m_componentInstance != null )
{
- try
- {
- // Get the bind method
- m_componentManager.log( LogService.LOG_DEBUG, "getting bind: " + m_dependencyMetadata.getBind(),
- m_componentManager.getComponentMetadata(), null );
- if ( m_bind == null )
+ return m_bind.invoke(
+ m_componentInstance,
+ new BindMethod.Service()
{
- m_bind = getBindingMethod( m_dependencyMetadata.getBind(), m_componentInstance.getClass(),
- m_dependencyMetadata.getInterface() );
-
- // 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 )
+ public ServiceReference getReference()
{
- m_componentManager.log( LogService.LOG_ERROR, "bind() method not found", m_componentManager
- .getComponentMetadata(), null );
- return true;
+ bindService( ref );
+ return ref;
}
- // 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_bindUsesReference )
- {
- parameter = ref;
-
- // mark this service as bound using the special sentinel
- bindService( ref );
- }
- else
- {
- // get the service, fail binding if the service is not
- // available (any more)
- parameter = getService( ref );
- if ( parameter == null )
+ public Object getInstance()
{
- m_componentManager.log( LogService.LOG_INFO, "Dependency Manager: Service " + ref
- + " has already gone, not binding", m_componentManager.getComponentMetadata(), null );
- return false;
+ return getService( ref );
}
}
-
- // Invoke the method
- m_bind.invoke( m_componentInstance, new Object[]
- { parameter } );
-
- m_componentManager.log( LogService.LOG_DEBUG, "bound: " + getName() + "/"
- + ref.getProperty( Constants.SERVICE_ID ), m_componentManager.getComponentMetadata(), null );
-
- return true;
- }
- 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
- m_componentManager.log( LogService.LOG_ERROR, "bind() method cannot be called", m_componentManager
- .getComponentMetadata(), ex );
- 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.log( LogService.LOG_ERROR, "DependencyManager : exception while invoking "
- + m_dependencyMetadata.getBind() + "()", m_componentManager.getComponentMetadata(), ex );
- return true;
- }
+ );
}
- else if ( m_componentManager.getComponentMetadata().isImmediate() == false )
+ else if ( !m_componentManager.getComponentMetadata().isImmediate() )
{
m_componentManager.log( LogService.LOG_DEBUG,
"DependencyManager : Delayed component not yet created, assuming bind method call succeeded",
@@ -1222,74 +1085,27 @@
* unbound
* @return true if the call was successful, false otherwise
*/
- private void invokeUnbindMethod( ServiceReference ref )
+ private void invokeUnbindMethod( final ServiceReference ref )
{
// The unbind method is only invoked if the implementation object is not
// null. This is valid for both immediate and delayed components
if ( m_componentInstance != null )
{
- try
- {
- // Get the bind method
- m_componentManager.log( LogService.LOG_DEBUG, "getting unbind: " + m_dependencyMetadata.getUnbind(),
- m_componentManager.getComponentMetadata(), null );
- if ( m_unbind == null )
+ m_unbind.invoke(
+ m_componentInstance,
+ new BindMethod.Service()
{
- m_unbind = getBindingMethod( m_dependencyMetadata.getUnbind(), m_componentInstance.getClass(),
- m_dependencyMetadata.getInterface() );
-
- if ( m_unbind == null )
+ public ServiceReference getReference()
{
- // 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.log( LogService.LOG_ERROR, "unbind() method not found", m_componentManager
- .getComponentMetadata(), null );
+ return ref;
}
- // cache whether the unbind method takes a reference
- m_unbindUsesReference = SERVICE_REFERENCE_CLASS.equals( m_unbind.getParameterTypes()[0] );
- }
- // Get the parameter
- Object parameter = null;
- if ( m_unbindUsesReference )
- {
- parameter = ref;
- }
- else
- {
- parameter = getService( ref );
- if ( parameter == null )
+ public Object getInstance()
{
- m_componentManager.log( LogService.LOG_INFO, "Dependency Manager: Service " + ref
- + " has already gone, not unbinding", m_componentManager.getComponentMetadata(), null );
+ return getService( ref );
}
}
-
- m_unbind.invoke( m_componentInstance, new Object[]
- { parameter } );
-
- m_componentManager.log( LogService.LOG_DEBUG, "unbound: " + getName() + "/"
- + ref.getProperty( Constants.SERVICE_ID ), m_componentManager.getComponentMetadata(), null );
- }
- 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
- m_componentManager.log( LogService.LOG_ERROR, "unbind() method cannot be called", m_componentManager
- .getComponentMetadata(), ex );
- }
- catch ( InvocationTargetException ex )
- {
- // 112.5.13 If an unbind method throws an exception, SCR must
- // log an error message containing the exception [...]
- m_componentManager
- .log( LogService.LOG_ERROR, "DependencyManager : exception while invoking "
- + m_dependencyMetadata.getUnbind() + "()", m_componentManager.getComponentMetadata(), ex
- .getCause() );
- }
-
+ );
}
else
{
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/UnbindMethod.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/UnbindMethod.java
new file mode 100644
index 0000000..90797cb
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/UnbindMethod.java
@@ -0,0 +1,40 @@
+/*
+ * 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.manager;
+
+
+/**
+ * Component method to be invoked on service unbinding.
+ */
+class UnbindMethod extends BindMethod
+{
+
+ UnbindMethod( final String methodName, final Class componentClass, final String referenceName,
+ final String referenceClassName, final Logger logger )
+ {
+ super( methodName, componentClass, referenceName, referenceClassName, logger );
+ }
+
+
+ protected String getMethodNamePrefix()
+ {
+ return "un";
+ }
+
+}
\ No newline at end of file
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/manager/BindMethodTest.java b/scr/src/test/java/org/apache/felix/scr/impl/manager/BindMethodTest.java
new file mode 100644
index 0000000..9fd1acd
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/impl/manager/BindMethodTest.java
@@ -0,0 +1,367 @@
+/*
+ * 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.manager;
+
+
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+
+public class BindMethodTest extends TestCase
+{
+
+ private ServiceReference m_serviceReference;
+ private FakeService m_serviceInstance;
+ private BindMethod.Service m_service;
+
+
+ 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;
+ }
+
+
+ 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 } );
+ }
+
+
+ public void test_Unexistent()
+ {
+ System.out.println();
+ final T1 t1 = new T1();
+ createMethod( "unexistent", T1.class ).invoke( t1, m_service );
+ assertNull( t1.callPerformed );
+ }
+
+
+ public void test_privateT1()
+ {
+ System.out.println();
+ final T1 t1 = new T1();
+ createMethod( "privateT1", T1.class ).invoke( t1, m_service );
+ assertNull( t1.callPerformed );
+ }
+
+
+ public void test_protectedT1()
+ {
+ System.out.println();
+ final T1 t1 = new T1();
+ createMethod( "protectedT1", T1.class ).invoke( t1, m_service );
+ assertNull( t1.callPerformed );
+ }
+
+
+ public void test_protectedT1SR()
+ {
+ System.out.println();
+ final T1 t1 = new T1();
+ createMethod( "protectedT1SR", T1.class ).invoke( t1, m_service );
+ assertEquals( "protectedT1SR", t1.callPerformed );
+ }
+
+
+ public void test_protectedT1SI()
+ {
+ System.out.println();
+ final T1 t1 = new T1();
+ createMethod( "protectedT1SI", T1.class ).invoke( t1, m_service );
+ assertEquals( "protectedT1SI", t1.callPerformed );
+ }
+
+
+ public void test_protectedT1SSI()
+ {
+ System.out.println();
+ final T1 t1 = new T1();
+ createMethod( "protectedT1SSI", T1.class ).invoke( t1, m_service );
+ assertEquals( "protectedT1SSI", t1.callPerformed );
+ }
+
+
+ public void test_protectedT1SSI_onT2()
+ {
+ System.out.println();
+ final T2 t2 = new T2();
+ createMethod( "protectedT1SSI", T2.class ).invoke( t2, m_service );
+ assertEquals( "protectedT1SSI", t2.callPerformed );
+ }
+
+
+ public void test_publicT1()
+ {
+ System.out.println();
+ final T1 t1 = new T1();
+ createMethod( "publicT1", T1.class ).invoke( t1, m_service );
+ assertNull( t1.callPerformed );
+ }
+
+
+ public void test_publicT1SR()
+ {
+ System.out.println();
+ final T1 t1 = new T1();
+ createMethod( "publicT1SR", T1.class ).invoke( t1, m_service );
+ assertEquals( "publicT1SR", t1.callPerformed );
+ }
+
+
+ public void test_publicT1SR_onT2()
+ {
+ System.out.println();
+ final T2 t2 = new T2();
+ createMethod( "publicT1SR", T2.class ).invoke( t2, m_service );
+ assertEquals( "publicT1SR", t2.callPerformed );
+ }
+
+
+ public void test_publicT1SI()
+ {
+ System.out.println();
+ final T1 t1 = new T1();
+ createMethod( "publicT1SI", T1.class ).invoke( t1, m_service );
+ assertEquals( "publicT1SI", t1.callPerformed );
+ }
+
+
+ public void test_publicT1SIMap()
+ {
+ System.out.println();
+ final T1 t1 = new T1();
+ createMethod( "publicT1SIMap", T1.class ).invoke( t1, m_service );
+ assertEquals( "publicT1SIMap", t1.callPerformed );
+ }
+
+
+ public void test_publicT1SI_onT2()
+ {
+ System.out.println();
+ final T2 t2 = new T2();
+ createMethod( "publicT1SI", T2.class ).invoke( t2, m_service );
+ assertEquals( "publicT1SI", t2.callPerformed );
+ }
+
+
+ public void test_publicT1SSI()
+ {
+ System.out.println();
+ final T1 t1 = new T1();
+ createMethod( "publicT1SSI", T1.class ).invoke( t1, m_service );
+ assertEquals( "publicT1SSI", t1.callPerformed );
+ }
+
+
+ public void test_publicT1SSI_onT2()
+ {
+ System.out.println();
+ final T2 t2 = new T2();
+ createMethod( "publicT1SSI", T2.class ).invoke( t2, m_service );
+ assertEquals( "publicT1SSI", t2.callPerformed );
+ }
+
+ private static interface SuperFakeService
+ {
+
+ }
+
+ private static interface FakeService extends SuperFakeService
+ {
+
+ }
+
+ private static class T1
+ {
+
+ String callPerformed = null;
+
+
+ private void privateT1()
+ {
+ callPerformed = "privateT1";
+ }
+
+
+ protected void protectedT1()
+ {
+ callPerformed = "protectedT1";
+ }
+
+
+ protected void protectedT1SR( ServiceReference sr )
+ {
+ if ( sr != null )
+ {
+ callPerformed = "protectedT1SR";
+ }
+ else
+ {
+ callPerformed = "protectedT1SR with null param";
+ }
+ }
+
+
+ protected void protectedT1SI( FakeService si )
+ {
+ if ( si != null )
+ {
+ callPerformed = "protectedT1SI";
+ }
+ else
+ {
+ callPerformed = "protectedT1SI with null param";
+ }
+ }
+
+
+ protected void protectedT1SSI( SuperFakeService si )
+ {
+ if ( si != null )
+ {
+ callPerformed = "protectedT1SSI";
+ }
+ else
+ {
+ callPerformed = "protectedT1SSI with null param";
+ }
+ }
+
+
+ protected void publicT1()
+ {
+ callPerformed = "publicT1";
+ }
+
+
+ public void publicT1SR( ServiceReference sr )
+ {
+ if ( sr != null )
+ {
+ callPerformed = "publicT1SR";
+ }
+ else
+ {
+ callPerformed = "publicT1SR with null param";
+ }
+ }
+
+
+ public void publicT1SI( FakeService si )
+ {
+ if ( si != null )
+ {
+ callPerformed = "publicT1SI";
+ }
+ else
+ {
+ callPerformed = "publicT1SI with null param";
+ }
+ }
+
+
+ public void publicT1SIMap( FakeService si, Map props )
+ {
+ if ( si != null && props != null && props.size() > 0 )
+ {
+ callPerformed = "publicT1SIMap";
+ }
+ else if ( si == null )
+ {
+ callPerformed = "publicT1SIMap with null service instance";
+ }
+ else if ( props == null )
+ {
+ callPerformed = "publicT1SIMap with null props";
+ }
+ else
+ {
+ callPerformed = "publicT1SIMap with empty props";
+ }
+
+ }
+
+
+ public void publicT1SSI( SuperFakeService si )
+ {
+ if ( si != null )
+ {
+ callPerformed = "publicT1SSI";
+ }
+ else
+ {
+ callPerformed = "publicT1SSI with null param";
+ }
+ }
+ }
+
+ private class T2 extends T1
+ {
+
+ }
+
+
+ public BindMethod createMethod( final String methodName, final Class componentClass )
+ {
+ return new BindMethod( methodName, componentClass, "reference", FakeService.class.getName(), new SysOutLogger() );
+ }
+
+ private static class SysOutLogger implements BindMethod.Logger
+ {
+
+ private static final String[] LEVELS = new String[]
+ { "ERROR", "WARNING", "INFO", "DEBUG" };
+
+
+ public void log( int level, String message )
+ {
+ log( level, message, null );
+ }
+
+
+ public void log( int level, String message, Throwable ex )
+ {
+ System.out.println( LEVELS[level - 1] + " - " + message );
+ if ( ex != null )
+ {
+ System.out.println( ex.getClass().getName() + "-" + ex.getMessage() );
+ }
+ }
+ }
+
+}