/** * Copyright 2005 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com * * Licensed 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.bushe.lang.reflect; import java.lang.reflect.*; /** * An implementation of the {@link InvocationHandler} interface that * can be used to create a dynamic proxy that, when invoked, will * call a specified method. This allows any class to essentially * implement an interface without declaring that is implements the * interface, and have any method called when the methods of that * interface are invoked. * <p> * The method can be called on a provided instance or can be a static * class method. * <p> * The method can accept the args of the interface method, or accept * no args at all. * <p> * See {@link org.bushe.swing.action.ActionManager} for an example * usage that allows any class to receive callbacks for ActionListener * without implementing ActionListener. * <p> * @author Michael Bushe * @version 1.0 */ public class MethodCallbackInvocationHandler implements InvocationHandler { Object target; Method method; boolean useArgs; public static Object createMethodCallbackProxy(Object callback, String method, Class[] args, Class implementingInterface, Class[] arrayOfInterfaces) throws UnsupportedOperationException, SecurityException, NoSuchMethodException, IllegalArgumentException { if (callback == null) { throw new IllegalArgumentException("Handler cannot be null."); } if (method == null) { throw new IllegalArgumentException("Method cannot be null."); } //get the callback class and the method to invoke boolean methodShouldBeStatic = false; Method methodToInvoke = null; Class callbackClass = null; if (callback instanceof Class) { methodShouldBeStatic = true; callbackClass = (Class) callback; } else { callbackClass = callback.getClass(); } //first look for action event signature try { methodToInvoke = callbackClass.getMethod(method, args); } catch (NoSuchMethodException ex) { //then use the no arg signature methodToInvoke = callbackClass.getMethod(method, (Class[])null); } if (methodToInvoke == null) { throw new NoSuchMethodException("Callback Method named " + method + " not found in class " + callbackClass); } boolean isStaticMethod = Modifier.isStatic(methodToInvoke.getModifiers()); if (isStaticMethod && methodShouldBeStatic) { throw new NoSuchMethodException("Callback Method named " + method + " must be static in class " + callbackClass); } return Proxy.newProxyInstance(MethodCallbackInvocationHandler.class.getClassLoader(), arrayOfInterfaces, new MethodCallbackInvocationHandler(implementingInterface, callback, methodToInvoke)); } /** * Create a handler implements the given interface by calling the * given method on the given object, passing the args of the inteface * calls if specified. * * @param interfac the interface this proxy handler implements * @param callback the object that will be called, ignored (can be null) for * static methods. * @param m the method to invoke on the target (or on the class if the * method is static), cannot be null * @throws IllegalArgumentException if method is null, or if target is * null and the method is not static, or if the args of the method * are anything except one ActionEvent or none at all. */ public MethodCallbackInvocationHandler(Class interfac, Object callback, Method m) { this.target = callback; this.method = m; if (m == null) { throw new IllegalArgumentException("Method is null."); } if (!Modifier.isStatic(m.getModifiers()) && target == null) { throw new IllegalArgumentException("Method is static and target is null."); } Class[] cl = m.getParameterTypes(); if (cl.length > 0) { this.useArgs = true; } } /** * InvocationHandler implementation, invokes the method */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (useArgs) { this.method.invoke(target, args); } else { this.method.invoke(target, (Object[])null); } return null; } }