| /******************************************************************************* |
| * Copyright (c) 2005 IBM Corporation. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.equinox.ds.instance; |
| |
| import java.lang.reflect.*; |
| import org.eclipse.equinox.ds.Log; |
| import org.eclipse.equinox.ds.model.ComponentDescription; |
| import org.eclipse.equinox.ds.model.ComponentConfiguration; |
| import org.eclipse.equinox.ds.resolver.Reference; |
| import org.eclipse.equinox.ds.service.ComponentInstanceImpl; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.service.component.ComponentContext; |
| import org.osgi.service.log.LogService; |
| |
| /** |
| * Invoke a method on a Service Component implementation class instance: |
| * activate, deactivate, bind or unbind |
| * |
| * @version $Revision: 1.1 $ |
| */ |
| |
| class InvokeMethod { |
| |
| private BuildDispose buildDispose; |
| |
| InvokeMethod(BuildDispose buildDispose) { |
| this.buildDispose = buildDispose; |
| } |
| |
| /** |
| * Invoke the activate method of the Service Component if one exists |
| * |
| * @param instance The instance of the component |
| * @param context The component context |
| */ |
| void activateComponent(Object instance, ComponentContext context) throws IllegalAccessException, InvocationTargetException { |
| |
| //cache activate method |
| ComponentDescription cd = ((ComponentInstanceImpl) context.getComponentInstance()).getComponentConfiguration().getComponentDescription(); |
| Method method = cd.getActivateMethod(); |
| if (method == null && !cd.isActivateMethodInitialized()) { |
| method = findActivateOrDeactivateMethod("activate", instance.getClass()); |
| //also sets cd.activateMethodInitialized flag |
| cd.setActivateMethod(method); |
| } |
| |
| // Create an array of parameters to pass to the method |
| // The activate method requires the ComponentContext |
| Object[] parameterTypes = new Object[] {context}; |
| |
| if (method != null) { |
| invokeMethod(method, instance, parameterTypes); |
| } |
| } |
| |
| /** |
| * Invoke the deactivate method of the Service Component if one exists |
| * |
| * @param instance The instance of the component |
| * @param context The component context |
| */ |
| void deactivateComponent(Object instance, ComponentContext context) throws IllegalAccessException, InvocationTargetException { |
| |
| //cache deactivate method |
| ComponentDescription cd = ((ComponentInstanceImpl) context.getComponentInstance()).getComponentConfiguration().getComponentDescription(); |
| Method method = cd.getDeactivateMethod(); |
| if (method == null && !cd.isDeactivateMethodInitialized()) { |
| method = findActivateOrDeactivateMethod("deactivate", instance.getClass()); |
| //also sets cd.deactivateMethodInitialized flag |
| cd.setDeactivateMethod(method); |
| } |
| |
| // Create an array of parameters to pass to the method |
| // The deactivate method requires the ComponentContext |
| Object[] parameterTypes = new Object[] {context}; |
| |
| if (method != null) { |
| invokeMethod(method, instance, parameterTypes); |
| } |
| } |
| |
| /** |
| * Invoke a bind method of a Service Component |
| * |
| * @param bind |
| * @param instance |
| * @param param service object or {@link ServiceReference} |
| * |
| * @throws IllegalAccessException |
| * @throws InvocationTargetException |
| */ |
| void bindComponent(Method bindMethod, Object instance, Object param) throws IllegalAccessException, InvocationTargetException { |
| // Create an array of parameters to pass to the method |
| Object[] parameterTypes = new Object[] {param}; |
| invokeMethod(bindMethod, instance, parameterTypes); |
| } |
| |
| /** |
| * unbind method of the Service Component |
| * |
| * @param unbind |
| * @param instance |
| * @param param service object or {@link ServiceReference} |
| * |
| * @throws IllegalAccessException |
| * @throws InvocationTargetException |
| */ |
| void unbindComponent(Method unbindMethod, Object instance, Object param) throws IllegalAccessException, InvocationTargetException { |
| // Create an array of parameters to pass to the method |
| Object[] parameterTypes = new Object[] {param}; |
| invokeMethod(unbindMethod, instance, parameterTypes); |
| } |
| |
| /** |
| * invokeMethod - invoke a Method on the Service Compoent via reflection |
| * |
| * @param method- the method name to invoke |
| * @param instance - instance to invoke method on |
| * @param parameterTypes - array of parameters to pass to the method |
| * |
| * @throws IllegalAccessException |
| * @throws InvocationTargetException |
| */ |
| |
| private void invokeMethod(Method method, Object instance, Object[] parameterTypes) throws IllegalAccessException, InvocationTargetException { |
| |
| // If the method is declared protected or public, SCR will call the |
| // method |
| int mod = method.getModifiers(); |
| if ((Modifier.isProtected(mod)) || (Modifier.isPublic(mod))) { |
| // if the method is protected must set accessibility(true) to invoke |
| // it |
| if (Modifier.isProtected(mod)) |
| method.setAccessible(true); |
| // invoke the method |
| method.invoke(instance, parameterTypes); |
| } |
| } |
| |
| private static final Class[] PARAM_COMPONENTCONTEXT = new Class[] {ComponentContext.class}; |
| private static final Class[] PARAM_SERVICEREFERENCE = new Class[] {ServiceReference.class}; |
| |
| /** |
| * Search through class and the superclasses for an activate or deactivate |
| * method. |
| * |
| * If method if found but not public or protected, log an error and return null |
| * |
| * @param methodName name of method to look for |
| * @param consumerClass Object to look in |
| * @return method or null if not found |
| */ |
| private Method findActivateOrDeactivateMethod(String methodName, Class consumerClass) { |
| Method method = null; |
| while (!consumerClass.equals(java.lang.Object.class) && method == null) { |
| |
| // search this class' methods |
| try { |
| method = consumerClass.getDeclaredMethod(methodName, PARAM_COMPONENTCONTEXT); |
| } catch (NoSuchMethodException e) { |
| // we'll try the superclass |
| } |
| if (method != null) |
| break; |
| |
| // we couldn't find the method - try the superclass |
| consumerClass = consumerClass.getSuperclass(); |
| } |
| |
| // if method is not protected or public, log error message |
| if (method != null) { |
| int modifier = method.getModifiers(); |
| if (!(Modifier.isProtected(modifier) || Modifier.isPublic(modifier))) { |
| // log error |
| Log.log(LogService.LOG_ERROR, "[SCR] Method " + methodName + " is not protected or public."); |
| method = null; |
| } |
| } |
| |
| return method; |
| } |
| |
| /** |
| * Search through class and the superclasses for a bind or unbind method. |
| * |
| * See OSGi R4 Specification section 112.3.1 "Accessing Services" for an |
| * explanation of the method search algorithm used for bind and unbind |
| * methods. |
| * |
| * Searching for the bind or unbind method may require a service object. If |
| * the object has not already been acquired, this method may call |
| * {@link BuildDispose#getService(ComponentConfiguration, Reference, ServiceReference)} |
| * to get it. |
| * |
| * If method can not be found we log an error and return null. |
| * |
| * @param componentInstance Object to look in |
| * @param reference Reference object |
| * @param serviceReference |
| * @param methodName name of method to look for |
| * |
| * @return the method or null if no method was found |
| * |
| */ |
| Method findBindOrUnbindMethod(ComponentInstanceImpl componentInstance, Reference reference, ServiceReference serviceReference, String methodName) { |
| Class consumerClass = componentInstance.getInstance().getClass(); |
| Object serviceObject = null; |
| Class serviceObjectClass = null; |
| Class interfaceClass = null; |
| Class[] param_interfaceClass = null; |
| Method method = null; |
| while (consumerClass != null) { |
| |
| // search this class' methods |
| // look for various forms of bind methods |
| |
| // 1) check for bind(ServiceReference) method |
| try { |
| method = consumerClass.getDeclaredMethod(methodName, PARAM_SERVICEREFERENCE); |
| } catch (NoSuchMethodException e) { |
| } |
| if (method != null) |
| break; |
| |
| // we need a serviceObject to keep looking, create one if necessary |
| if (serviceObject == null) { |
| serviceObject = reference.getServiceObject(serviceReference); |
| if (serviceObject == null) { |
| serviceObject = buildDispose.getService(reference, serviceReference); |
| } |
| if (serviceObject == null) { |
| // we could not create a serviceObject because of |
| // circularity |
| return null; |
| } |
| reference.addServiceReference(serviceReference, serviceObject); |
| serviceObjectClass = serviceObject.getClass(); |
| |
| // figure out the interface class - this is guaranteed to |
| // succeed or else |
| // the framework would not have let us have the service object |
| Class searchForInterfaceClass = serviceObjectClass; |
| String interfaceName = reference.getReferenceDescription().getInterfacename(); |
| while (searchForInterfaceClass != null) { |
| // first look through interfaces |
| Class[] interfaceClasses = searchForInterfaceClass.getInterfaces(); |
| for (int i = 0; i < interfaceClasses.length; i++) { |
| if (interfaceClasses[i].getName().equals(interfaceName)) { |
| interfaceClass = interfaceClasses[i]; |
| break; |
| } |
| } |
| if (interfaceClass != null) { |
| break; |
| } |
| |
| // also check the class itself |
| if (searchForInterfaceClass.getName().equals(interfaceName)) { |
| interfaceClass = searchForInterfaceClass; |
| break; |
| } |
| |
| // advance up the superclasses |
| searchForInterfaceClass = searchForInterfaceClass.getSuperclass(); |
| } |
| |
| param_interfaceClass = new Class[] {interfaceClass}; |
| |
| } // end if(serviceObject == null) |
| |
| // 2) check for bind(Service interface) method |
| try { |
| method = consumerClass.getDeclaredMethod(methodName, param_interfaceClass); |
| } catch (NoSuchMethodException e) { |
| } |
| if (method != null) |
| break; |
| |
| // 3) check for bind(class.isAssignableFrom(serviceObjectClass)) |
| // method |
| Method[] methods = consumerClass.getDeclaredMethods(); |
| for (int i = 0; i < methods.length; i++) { |
| Class[] params = methods[i].getParameterTypes(); |
| if (params.length == 1 && methods[i].getName().equals(methodName) && params[0].isAssignableFrom(serviceObjectClass)) { |
| |
| method = methods[i]; |
| break; |
| } |
| } |
| if (method != null) |
| break; |
| |
| // we couldn't find the method - try the superclass |
| consumerClass = consumerClass.getSuperclass(); |
| } |
| |
| if (method == null) { |
| // log error = we could not find the method |
| Log.log(LogService.LOG_ERROR, "[SCR] Could not find method " + methodName + "."); |
| return null; |
| } |
| |
| // if method is not protected or public, log error message |
| int modifier = method.getModifiers(); |
| if (!(Modifier.isProtected(modifier) || Modifier.isPublic(modifier))) { |
| // log error |
| Log.log(LogService.LOG_ERROR, "[SCR] Method " + methodName + " is not protected or public."); |
| return null; |
| } |
| |
| return method; |
| } |
| |
| } |