December 19, 2011
Delegate dalam Java
secara default java tidaklah mendukung Delegate , tetapi dengan fleksibilitas dari java memungkinkan kita mendefinisikan delegate sendiri
pertama yang dibutuhkan adalah class Delegator,java
package goblooge.delegate; import java.lang.reflect.*; import java.util.List; import java.util.ArrayList; /** * com.lordjoe.csharp.Delegator * Class representing a delegate tamplate - * also a factory treturning the real delegate object * @author Steve Lewis smlewis@lordjoe.com */ public class Delegator { public static final Method[] EMPTY_METHOD_ARRAY = {}; public static final Object[] EMPTY_OBJECT_ARRAY = {}; public static final Delegator[] EMPTY_ARRAY = {}; // convenience implementation public static final Delegator RUNNABLE_DELEGATE = new Delegator(Runnable.class); /** * Convenience method to make a runnable delegate * @param item non-null target object * @param methodName non-null name of a method of type void () * @return non-null Runnable proxy */ public static Runnable buildRunnable(Object item,String methodName) { return((Runnable)RUNNABLE_DELEGATE.build(item, methodName)); } /** * Convenience method to make a runnable delegate * @param item non-null target class * @param methodName non-null name of a method of type void () * @return non-null Runnable proxy */ public static Runnable buildRunnable(Class item,String methodName) { return((Runnable)RUNNABLE_DELEGATE.build(item, methodName)); } private final Class m_Interface; // may be null private final Class m_Return; private final Class[] m_Arguments; /** * @param params non-null array of arguments * @param retClass possibly null return class null says do not care */ public Delegator(Class[] params,Class retClass) { m_Interface = null; m_Return = retClass; m_Arguments = params; } /** * @param TheInterface an non-null interface with EXACTLY one method */ public Delegator(Class TheInterface) { m_Interface = TheInterface; Method met = findMethod(TheInterface); m_Return = met.getReturnType(); m_Arguments = met.getParameterTypes(); } /** * accessor for return class */ public Class getReturn() { return m_Return; } /** * accessor for argument classes */ public Class[] getArguments() { return m_Arguments; } public Class getInterface() { return m_Interface; } /** * * @param target non-null class with a bindable static method * @param MethodName name of the static method * @return non-null IDelegate if getInterface() is non-null it will be a * dynamic prozy implementing that interface */ public IDelegate build(Class target,String MethodName) { Class myInterface = getInterface(); DelegateProxy theDelegate = new DelegateProxy(null,target,MethodName,this); if(myInterface != null) { Class[] interfaces = { myInterface,IDelegate.class }; IDelegate ret = (IDelegate)java.lang.reflect.Proxy.newProxyInstance( target.getClassLoader(), interfaces,theDelegate); return(ret); } return((IDelegate)theDelegate); } /** * * @param target non-null target with a bindable method * @param MethodName name of the method * @return non-null IDelegate if getInterface() is non-null it will be a * dynamic prozy implementing that interface */ public IDelegate build(Object target,String MethodName) { Class myInterface = getInterface(); DelegateProxy theDelegate = new DelegateProxy(target,target.getClass(),MethodName,this); if(myInterface != null) { // build a dynamic proxy Class[] interfaces = { myInterface,IDelegate.class }; IDelegate ret = (IDelegate)java.lang.reflect.Proxy.newProxyInstance( target.getClass().getClassLoader(), interfaces,theDelegate); return(ret); } if(!(theDelegate instanceof IDelegate)) throw new ClassCastException(); return((IDelegate)theDelegate); } protected class DelegateProxy implements IDelegate,InvocationHandler { private final Method m_Method; private final Object m_Target; private final Delegator m_Template; /** * constructor supplying a Class passing in types not template * @param target possibly null target if null the method must be static * @param target non-null class implementing a suitable method * @param target non-null object implementing a suitable static method * @param MethodName nun-null name of a public static method in target * @param template non-null template with the required arguemts and return */ protected DelegateProxy(Object target,Class targetClass,String MethodName,Delegator template) { m_Template = template; m_Target = target; Method meth = findSuitableMethod(targetClass,MethodName,template); m_Method = meth; } /** * convenience call to handle case of no arguments * @return whatever is returned */ public Object invoke() throws IllegalArgumentException,DelegateInvokeException { return(invoke(EMPTY_OBJECT_ARRAY)); } /** * convenience call to handle case of one argument * @param arg some argument * @return whatever is returned */ public Object invoke(Object arg) throws IllegalArgumentException,DelegateInvokeException { Object[] args = { arg }; return(invoke(args)); } /** * convenience call to handle case of two argument * @param arg1 some argument * @param arg2 some argument * @return whatever is returned */ public Object invoke(Object arg1, Object arg2) throws IllegalArgumentException,DelegateInvokeException { Object[] args = { arg1, arg2 }; return(invoke(args)); } /** * method required by InvocationHandler so we can build dynamic Proxys * @param proxy object for which we are a proxy (ignored) * @param method method to call (ignored) * @param args arguments to pass * @return whatever is returned primitive types are wrapped */ public Object invoke(Object proxy, Method method, Object[] args) { return(invoke(args)); } /** * basic call to method * @param args method arguments * @return whatever is returned */ public Object invoke(Object[] args) throws IllegalArgumentException,DelegateInvokeException { // validateArgs(args); try { Object ret = getMethod().invoke(getTarget(),args); return(ret); } catch(IllegalAccessException ex1) { throw new IllegalStateException("Bad Delgate State" + ex1.getMessage()); // should not happen } catch(InvocationTargetException ex1) { throw new Delegator.DelegateInvokeException(ex1.getCause()); } } /** * if uncommented in invoke this code will throw an IllegalArgument call * if arguments are of the wrong type */ protected void validateArgs(Object[] args) throws IllegalArgumentException { Class[] MyArgs = getArguments(); if(args.length != MyArgs.length) throw new IllegalArgumentException("Delegate required " + MyArgs.length + "arguments"); for(int i = 0; i < args.length; i++) { if(!MyArgs[i].isInstance(args[i]) ) throw new IllegalArgumentException("Argument " + i + " must be of class " + MyArgs[i].getName()); } } /** * accessor for the method */ public Method getMethod() { return m_Method; } /** * accessor for the target */ public Object getTarget() { return m_Target; } }// end class DelegateProxy /** * All problems become this type of exception * As a runtime we do not impose burdens on the calling code */ public static class DelegateInvokeException extends RuntimeException { public DelegateInvokeException(Throwable cause) { super(cause); } } // =================================================================== // static utility methods in this section identify the // method in verious targets // =================================================================== /** * utility method to test suitability */ protected static boolean isSuitableMethod(Method testMethod,Class[] args,Class retClass) { Class[] methodArgs = testMethod.getParameterTypes(); for(int i = 0; i < methodArgs.length; i++) { Class arg = methodArgs[i]; if(!arg.isAssignableFrom(args[i])) return(false); } // This is the only isValidReturn(testMethod,retClass); return(true); } /** * utility method to get candidate methods to search */ protected static Method[] getCandidateMethods(Class targetClass,String MethodName,int nargs) { Method[] possibilities = targetClass.getMethods(); List holder = new ArrayList(); for(int i = 0; i < possibilities.length; i++) { Method possibility = possibilities[i]; if( possibility.getName().equals(MethodName) && possibility.getParameterTypes().length == nargs && Modifier.isPublic(possibility.getModifiers())) holder.add(possibility); } return((Method[])holder.toArray(EMPTY_METHOD_ARRAY)); } /** * utility method to test return */ protected static boolean isValidReturn(Method test, Class retClass) { if(retClass == null) return(true); // we do not care if(test.getReturnType() == retClass) return(true); if(retClass.isAssignableFrom(test.getReturnType())) return(true); return(false); } /** * Utility method to locate a proper Method object */ protected static Method findSuitableMethod(Class targetClass,String MethodName,Delegator templ) { Class[] args = templ.getArguments(); Class retClass = templ.getReturn(); // perfect match try { Method ret = targetClass.getMethod(MethodName,args); if(!isValidReturn(ret,retClass)) throw new IllegalArgumentException("Requested method returns wrong type"); if(!Modifier.isPublic(ret.getModifiers())) throw new IllegalArgumentException("Requested method is not public"); return(ret); } catch(Exception ex) {} // on to try2 Method[] possibilities = getCandidateMethods(targetClass,MethodName,args.length); for(int i = 0; i < possibilities.length; i++) { Method possibility = possibilities[i]; if(isSuitableMethod(possibility,args,retClass)) return(possibility); } throw new IllegalArgumentException("No suitable method found"); } /** * utility code to find the one suitable method in the passed in interface. */ protected static Method findMethod(Class TheInterface) { if(!TheInterface.isInterface()) throw new IllegalArgumentException("DelegateTemplate must be constructed with an interface"); Method[] methods = TheInterface.getMethods(); Method ret = null; for(int i = 0; i < methods.length; i++) { Method test = methods[i]; if(Modifier.isAbstract(test.getModifiers())) { if(ret != null) throw new IllegalArgumentException("DelegateTemplate must be constructed "+ " with an interface implementing only one method!"); ret = test; } } if(ret == null) throw new IllegalArgumentException("DelegateTemplate must be constructed "+ " with an interface implementing exactly method!"); return(ret); } }
class kedua adalah IDelegate.java
package goblooge.delegate; /** * Interface implemnted by the object returned by Delegator.bind * Use this only when no suitable alternative interface is available * @author Steve Lewis * Date: May 9, 2002 **/ public interface IDelegate { /** * Thin wrapper in invoke * @param args possibly null array or args - null says none * @return possibly null return - primitive types are wrapped */ public Object invoke(Object[] args); /** * convenience call for 1 arg case * @param arg possibly null argument * @return possibly null return - primitive types are wrapped */ public Object invoke(Object arg); /** * convenience call for 2 arg case * @param arg1 possibly null argument * @param arg2 possibly null argument * @return possibly null return - primitive types are wrapped */ public Object invoke(Object arg1, Object arg2); /** * convenience call for no arg case * @return possibly null return - primitive types are wrapped */ public Object invoke(); }
Class terakjhir adalah TestDelegate.java
selesai