code: /**
   *   Copyright (c) Rich Hickey. All rights reserved.
   *   The use and distribution terms for this software are covered by the
   *   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
   *   which can be found in the file epl-v10.html at the root of this distribution.
   *   By using this software in any fashion, you are agreeing to be bound by
   * 	 the terms of this license.
   *   You must not remove this notice, or any other, from this software.
   **/
  
  /* rich Oct 4, 2007 */
  
  package clojure.lang;
  
  import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Method;
  
  public class ProxyHandler implements InvocationHandler{
  //method-name-string->fn
  final IPersistentMap fns;
  
  
  public ProxyHandler(IPersistentMap fns){
  	this.fns = fns;
  }
  
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
  	Class rt = method.getReturnType();
  	IFn fn = (IFn) fns.valAt(method.getName());
  	if(fn == null)
  		{
  		if(rt == Void.TYPE)
  			return null;
  		else if(method.getName().equals("equals"))
  			{
  			return proxy == args[0];
  			}
  		else if(method.getName().equals("hashCode"))
  			{
  			return System.identityHashCode(proxy);
  			}
  		else if(method.getName().equals("toString"))
  			{
  			return "Proxy: " + System.identityHashCode(proxy);
  			}
  		throw new UnsupportedOperationException();
  		}
  	Object ret = fn.applyTo(ArraySeq.create(args));
  	if(rt == Void.TYPE)
  		return null;
  	else if(rt.isPrimitive())
  		{
  		if(rt == Character.TYPE)
  			return ret;
  		else if(rt == Integer.TYPE)
  			return ((Number) ret).intValue();
  		else if(rt == Long.TYPE)
  			return ((Number) ret).longValue();
  		else if(rt == Float.TYPE)
  			return ((Number) ret).floatValue();
  		else if(rt == Double.TYPE)
  			return ((Number) ret).doubleValue();
  		else if(rt == Boolean.TYPE && !(ret instanceof Boolean))
  			return ret == null ? Boolean.FALSE : Boolean.TRUE;
  		else if(rt == Byte.TYPE)
  			return (byte) ((Number) ret).intValue();
  		else if(rt == Short.TYPE)
  			return (short) ((Number) ret).intValue();
  		}
  	return ret;
  }
  }
  