001 package org.codehaus.groovy.runtime;
002
003 import java.lang.reflect.InvocationHandler;
004 import java.lang.reflect.InvocationTargetException;
005 import java.lang.reflect.Method;
006
007 /**
008 * This class is a general adapter to map a call to an Java interface
009 * to a given delegate.
010 * <p>
011 * @author Ben Yu
012 * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
013 */
014 public abstract class ConversionHandler implements InvocationHandler {
015 private Object delegate;
016
017 /**
018 * Creates a ConversionHandler with an deleagte.
019 * @param delegate the delegate
020 * @throws IllegalArgumentException if the given delegate is null
021 */
022 public ConversionHandler(Object delegate) {
023 if (delegate==null) throw new IllegalArgumentException("delegate must not be null");
024 this.delegate = delegate;
025 }
026
027 /**
028 * gets the delegate.
029 * @return the delegate
030 */
031 public Object getDelegate(){
032 return delegate;
033 }
034
035 /**
036 * This method is a default implementation for the invoke method
037 * given in Invocationhandler. Any call to an method with an
038 * declaring class that is not Object is redirected to invokeCustom.
039 * Methods like tostring, equals and hashcode are called on the class
040 * itself instead of the delegate. It is better to overwrite the
041 * invokeCustom method where the Object related methods are filtered out.
042 *
043 * @see #invokeCustom(Object, Method, Object[])
044 * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
045 *
046 * @param proxy the proxy
047 * @param method the method
048 * @param args the arguments
049 * @return the result of the invocation by method or delegate
050 * @throws Throwable any exception caused by the delegate or the method
051 */
052 public Object invoke(Object proxy, Method method, Object[] args)
053 throws Throwable {
054 if(!isObjectMethod(method)){
055 return invokeCustom(proxy,method,args);
056 }
057 try {
058 return method.invoke(this, args);
059 } catch (InvocationTargetException ite) {
060 throw ite.getTargetException();
061 }
062 }
063
064 /**
065 * This method is called for all Methods not defined on Object.
066 * The delegate should be called here.
067 *
068 * @param proxy the proxy
069 * @param method the method
070 * @param args the arguments
071 * @return the result of the invocation of the delegate
072 * @throws Throwable any exception causes by the delegate
073 * @see #invoke(Object, Method, Object[])
074 * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
075 *
076 */
077 public abstract Object invokeCustom(Object proxy, Method method, Object[] args) throws Throwable;
078
079 /**
080 * Indicates whether some other object is "equal to" this one.
081 * The delegate is used if the class of the parameter and the
082 * current class are equal. In other cases the method will return
083 * false. The exact class is here used, if inheritance is needed,
084 * this method must be overwritten.
085 *
086 * @see java.lang.Object#equals(java.lang.Object)
087 */
088 public boolean equals(Object obj) {
089 if (obj!=null && obj.getClass()==this.getClass()){
090 return (((ConversionHandler)obj).getDelegate()).equals(obj);
091 } else {
092 return false;
093 }
094 }
095
096 /**
097 * Returns a hash code value for the delegate.
098 * @see java.lang.Object#hashCode()
099 */
100 public int hashCode() {
101 return delegate.hashCode();
102 }
103
104 /**
105 * Returns a String version of the delegate.
106 * @see java.lang.Object#toString()
107 */
108 public String toString() {
109 return delegate.toString();
110 }
111
112 private static boolean isObjectMethod(Method mtd){
113 return mtd.getDeclaringClass().equals(Object.class);
114 }
115 }