001: /*
002: * JProxy.java
003: *
004: * Copyright (C) 2002-2004 Peter Graves
005: * $Id: JProxy.java,v 1.4 2004/02/23 00:05:35 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.lisp;
023:
024: import java.lang.reflect.InvocationHandler;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.Proxy;
027: import java.util.HashMap;
028: import java.util.Map;
029: import java.util.WeakHashMap;
030:
031: public final class JProxy extends Lisp {
032: private static final Map table = new WeakHashMap();
033:
034: // ### %jnew-proxy
035: // %jnew-proxy interface &rest method-names-and-defs
036: private static final Primitive _JNEW_PROXY = new Primitive(
037: "%jnew-proxy", PACKAGE_JAVA, false,
038: "interface &rest method-names-and-defs") {
039: public LispObject execute(LispObject[] args)
040: throws ConditionThrowable {
041: int length = args.length;
042: if (length < 3 || length % 2 != 1)
043: return signal(new WrongNumberOfArgumentsException(this ));
044: Map lispDefinedMethods = new HashMap();
045: for (int i = 1; i < length; i = i + 2)
046: lispDefinedMethods.put(args[i].getStringValue(),
047: (Function) args[i + 1]);
048: Class iface = (Class) args[0].javaInstance();
049: Object proxy = Proxy.newProxyInstance(iface
050: .getClassLoader(), new Class[] { iface },
051: new LispHandler(table));
052: table.put(proxy, new Entry(iface, lispDefinedMethods));
053: return new JavaObject(proxy);
054: }
055: };
056:
057: private static class LispHandler implements InvocationHandler {
058: Map table;
059:
060: LispHandler(Map table) {
061: this .table = table;
062: }
063:
064: public Object invoke(Object proxy, Method method, Object[] args) {
065: String methodName = method.getName();
066:
067: if (methodName.equals("hashCode")) {
068: return new Integer(System.identityHashCode(proxy));
069: } else if (methodName.equals("equals")) {
070: return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
071: } else if (methodName.equals("toString")) {
072: return proxy.getClass().getName() + '@'
073: + Integer.toHexString(proxy.hashCode());
074: }
075:
076: if (table.containsKey(proxy)) {
077: Entry entry = (Entry) table.get(proxy);
078: Function f = entry.getLispMethod(methodName);
079: if (f != null) {
080: if (args == null) // method needs no argument
081: args = new Object[0];
082: LispObject[] lispArgs = new LispObject[args.length];
083: for (int i = 0; i < args.length; i++)
084: lispArgs[i] = new JavaObject(args[i]);
085: try {
086: LispObject result = f.execute(lispArgs);
087: return (method.getReturnType() == void.class ? null
088: : result.javaInstance());
089: } catch (ConditionThrowable t) {
090: t.printStackTrace();
091: }
092: }
093: }
094: return null;
095: }
096: }
097:
098: private static class Entry {
099: Class iface;
100: Map lispDefinedMethods;
101:
102: public Entry(Class iface, Map lispDefinedMethods) {
103: this .iface = iface;
104: this .lispDefinedMethods = lispDefinedMethods;
105: }
106:
107: public Function getLispMethod(String methodName) {
108: if (lispDefinedMethods.containsKey(methodName))
109: return (Function) lispDefinedMethods.get(methodName);
110: return null;
111: }
112: }
113: }
|