| /* |
| * 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.ipojo.util; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| |
| import org.apache.felix.ipojo.InstanceManager; |
| import org.apache.felix.ipojo.parser.FieldMetadata; |
| import org.apache.felix.ipojo.parser.MethodMetadata; |
| |
| /** |
| * A callback allows invoking a method on a POJO. |
| * This class supports both public, protected and private methods of the |
| * implementation class. This class also supports public method from super class. |
| * The {@link Method} object is computed once and this computation is delayed |
| * to the first invocation. |
| * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> |
| */ |
| public class Callback { |
| |
| /** |
| * The method object. |
| * Computed at the first call. |
| */ |
| protected Method m_methodObj; |
| |
| /** |
| * The name of the method to call. |
| */ |
| private String m_method; |
| |
| /** |
| * Is the method a static method ? |
| * This implies calling the method on <code>null</code> |
| */ |
| private boolean m_isStatic; |
| |
| /** |
| * The reference on the instance manager. |
| * Used to get POJO objects. |
| */ |
| private InstanceManager m_manager; |
| |
| /** |
| * The argument classes. |
| * This array contains the list of argument class names. |
| */ |
| private String[] m_args; |
| |
| /** |
| * Creates a Callback. |
| * If the argument array is not null the reflection type are computed. |
| * @see Callback#computeArguments(String[]) |
| * @param method the name of the method to call |
| * @param args the argument type name, or <code>null</code> if no arguments |
| * @param isStatic is the method a static method |
| * @param manager the instance manager of the component containing the method |
| */ |
| public Callback(String method, String[] args, boolean isStatic, InstanceManager manager) { |
| m_method = method; |
| m_isStatic = isStatic; |
| m_manager = manager; |
| if (args != null) { |
| computeArguments(args); |
| } else { |
| m_args = new String[0]; |
| } |
| } |
| |
| /** |
| * Creates a Callback. |
| * @param method the the name of the method to call |
| * @param args the argument classes |
| * @param isStatic the is the method a static method |
| * @param manager the the instance manager of the component containing the method |
| */ |
| public Callback(String method, Class[] args, boolean isStatic, InstanceManager manager) { |
| m_method = method; |
| m_isStatic = isStatic; |
| m_manager = manager; |
| m_args = new String[args.length]; |
| for (int i = 0; i < args.length; i++) { |
| m_args[i] = args[i].getName(); |
| } |
| } |
| |
| /** |
| * Creates a Callback. |
| * @param method the {@link MethodMetadata} obtained from manipulation |
| * metadata ({@link org.apache.felix.ipojo.parser.PojoMetadata}). |
| * @param manager the instance manager. |
| */ |
| public Callback(MethodMetadata method, InstanceManager manager) { |
| m_isStatic = false; |
| m_method = method.getMethodName(); |
| m_manager = manager; |
| computeArguments(method.getMethodArguments()); |
| } |
| |
| /** |
| * Computes arguments of the method. |
| * This method computes "reflection type" from given argument. |
| * @see FieldMetadata#getReflectionType(String) |
| * @param args the arguments of the method. |
| */ |
| private void computeArguments(String[] args) { |
| m_args = new String[args.length]; |
| for (int i = 0; i < args.length; i++) { |
| m_args[i] = FieldMetadata.getReflectionType(args[i]); |
| } |
| } |
| |
| /** |
| * Searches the {@link Method} in the given method arrays. |
| * @param methods the method array in which the method should be found |
| * @return the method object or <code>null</code> if not found |
| */ |
| private Method searchMethodInMethodArray(Method[] methods) { |
| for (int i = 0; i < methods.length; i++) { |
| // First check the method name |
| if (methods[i].getName().equals(m_method)) { |
| // Check arguments |
| Class[] clazzes = methods[i].getParameterTypes(); |
| if (clazzes.length == m_args.length) { // Test size to avoid useless loop |
| int argIndex = 0; |
| for (; argIndex < m_args.length; argIndex++) { |
| if (!m_args[argIndex].equals(clazzes[argIndex].getName())) { |
| break; |
| } |
| } |
| if (argIndex == m_args.length) { // No mismatch detected. |
| return methods[i]; // It is the looked method. |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Searches the {@link Method} object in the POJO by analyzing implementation |
| * class methods. The name of the method and the argument type are checked. |
| * @throws NoSuchMethodException if the method cannot be found either in the |
| * implementation class or in parent classes. |
| */ |
| protected void searchMethod() throws NoSuchMethodException { |
| Method[] methods = m_manager.getClazz().getDeclaredMethods(); |
| m_methodObj = searchMethodInMethodArray(methods); |
| |
| if (m_methodObj == null) { // look at parent classes |
| methods = m_manager.getClazz().getMethods(); |
| m_methodObj = searchMethodInMethodArray(methods); |
| } |
| |
| if (m_methodObj == null) { |
| throw new NoSuchMethodException(m_method); |
| } else { |
| if (! m_methodObj.isAccessible()) { |
| // If not accessible, try to set the accessibility. |
| m_methodObj.setAccessible(true); |
| } |
| } |
| } |
| |
| /** |
| * Invokes the method without arguments. |
| * If several the instance contains several objects, the method is invoked |
| * on every objects. |
| * @return the result of the invocation, <code>null</code> for <code>void</code> |
| * method, the last result for multi-object instance |
| * @throws NoSuchMethodException if Method is not found in the class |
| * @throws InvocationTargetException if the method throws an exception |
| * @throws IllegalAccessException if the method can not be invoked |
| */ |
| public Object call() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { |
| return call(new Object[0]); |
| } |
| |
| /** |
| * Invokes the method without arguments. |
| * The method is invokes on the specified object. |
| * @param instance the instance on which call the callback |
| * @return the result of the invocation, <code>null</code> for |
| * <code>void</code> method |
| * @throws NoSuchMethodException if the method was not found |
| * @throws IllegalAccessException if the method cannot be called |
| * @throws InvocationTargetException if an error happens in the method |
| */ |
| public Object call(Object instance) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { |
| return call(instance, new Object[0]); |
| } |
| |
| /** |
| * Invokes the method on every created objects with the specified |
| * arguments. |
| * @param arg the method arguments |
| * @return the result of the invocation, <code>null</code> for |
| * <code>void</code> method, the last result for instance containing |
| * several objects. |
| * @throws NoSuchMethodException if the callback method is not found |
| * @throws IllegalAccessException if the callback method cannot be called |
| * @throws InvocationTargetException if an error is thrown by the called method |
| */ |
| public Object call(Object[] arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { |
| if (m_methodObj == null) { |
| searchMethod(); |
| } |
| |
| if (m_isStatic) { |
| return m_methodObj.invoke(null, arg); |
| } else { |
| // Two cases : |
| // - if instances already exists : call on each instances |
| // - if no instance exists : create an instance |
| if (m_manager.getPojoObjects() == null) { |
| return m_methodObj.invoke(m_manager.getPojoObject(), arg); |
| } else { |
| Object newObject = null; |
| for (int i = 0; i < m_manager.getPojoObjects().length; i++) { |
| newObject = m_methodObj.invoke(m_manager.getPojoObjects()[i], arg); |
| } |
| return newObject; |
| } |
| } |
| } |
| |
| /** |
| * Invokes the method on the given object with the specified |
| * arguments. |
| * @param instance the instance on which call the method |
| * @param arg the argument array |
| * @return the result of the invocation, <code>null</code> for |
| * <code>void</code> method |
| * @throws NoSuchMethodException if the callback method is not found |
| * @throws IllegalAccessException if the callback method cannot be called |
| * @throws InvocationTargetException if an error is thrown by the called method |
| */ |
| public Object call(Object instance, Object[] arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { |
| if (m_methodObj == null) { |
| searchMethod(); |
| } |
| |
| return m_methodObj.invoke(instance, arg); |
| } |
| |
| /** |
| * Gets the method name. |
| * @return the method name |
| */ |
| public String getMethod() { |
| return m_method; |
| } |
| |
| /** |
| * Gets the method arguments. |
| * @return the arguments. |
| */ |
| public String[] getArguments() { |
| return m_args; |
| } |
| } |