[armedbear-cvs] r11369 - in branches/scripting/j/src/org/armedbear/lisp: . scripting

Alessio Stalla astalla at common-lisp.net
Thu Oct 30 06:30:26 UTC 2008


Author: astalla
Date: Thu Oct 30 06:30:25 2008
New Revision: 11369

Log:
Introduced jmake-invocation-handler and jmake-proxy.

Modified:
   branches/scripting/j/src/org/armedbear/lisp/Autoload.java
   branches/scripting/j/src/org/armedbear/lisp/JProxy.java
   branches/scripting/j/src/org/armedbear/lisp/autoloads.lisp
   branches/scripting/j/src/org/armedbear/lisp/java.lisp
   branches/scripting/j/src/org/armedbear/lisp/scripting/AbclScriptEngine.java

Modified: branches/scripting/j/src/org/armedbear/lisp/Autoload.java
==============================================================================
--- branches/scripting/j/src/org/armedbear/lisp/Autoload.java	(original)
+++ branches/scripting/j/src/org/armedbear/lisp/Autoload.java	Thu Oct 30 06:30:25 2008
@@ -489,6 +489,8 @@
         autoload(PACKAGE_EXT, "thread-unlock", "ThreadLock", true);
         autoload(PACKAGE_JAVA, "%jnew-proxy", "JProxy");
         autoload(PACKAGE_JAVA, "%jimplement-interface", "JProxy");
+        autoload(PACKAGE_JAVA, "%jmake-invocation-handler", "JProxy");
+        autoload(PACKAGE_JAVA, "%jmake-proxy", "JProxy");
         autoload(PACKAGE_JAVA, "%jnew-runtime-class", "RuntimeClass");
         autoload(PACKAGE_JAVA, "%jredefine-method", "RuntimeClass");
         autoload(PACKAGE_JAVA, "%jregister-handler", "JHandler");

Modified: branches/scripting/j/src/org/armedbear/lisp/JProxy.java
==============================================================================
--- branches/scripting/j/src/org/armedbear/lisp/JProxy.java	(original)
+++ branches/scripting/j/src/org/armedbear/lisp/JProxy.java	Thu Oct 30 06:30:25 2008
@@ -122,10 +122,104 @@
     }
   }
   
-  	//NEW IMPLEMENTATION by Alessio Stalla
+  	//NEW IMPLEMENTATION by Alessio Stalla 
   
-  	
+  	public static class LispInvocationHandler implements InvocationHandler {
+  		
+  		private Function function;
+  		private static Method hashCodeMethod;
+  		private static Method equalsMethod;
+  		private static Method toStringMethod;
+  		
+  		static {
+  			try {
+				hashCodeMethod = Object.class.getMethod("hashCode", new Class[] {});
+				equalsMethod = Object.class.getMethod("equals", new Class[] { Object.class });
+				toStringMethod = Object.class.getMethod("toString", new Class[] {});
+			} catch (Exception e) {
+				throw new Error("Something got horribly wrong - can't get a method from Object.class", e);
+			}
+  		}
+
+  		public LispInvocationHandler(Function function) {
+  			this.function = function;
+  		}
+  		
+		@Override
+		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+	    	if(hashCodeMethod.equals(method)) {
+	    		return proxy.hashCode();
+	    	}
+	    	if(equalsMethod.equals(method)) {
+	    		return proxy.equals(args[0]);
+	    	}
+	    	if(toStringMethod.equals(method)) {
+	    		return proxy.toString();
+	    	}
+	    	
+			LispObject[] lispArgs = new LispObject[args.length + 2];
+			lispArgs[0] = toLispObject(proxy);
+			lispArgs[1] = new JavaObject(method);
+			for(int i = 0; i < args.length; i++) {
+				lispArgs[i + 2] = toLispObject(args[i]);
+			}
+			Object retVal = (function.execute(lispArgs)).javaInstance();
+			/* DOES NOT WORK due to autoboxing!
+			if(retVal != null && !method.getReturnType().isAssignableFrom(retVal.getClass())) {
+				return error(new TypeError(new JavaObject(retVal), new JavaObject(method.getReturnType())));
+			}*/
+			return retVal;
+		}
+	}
   
+  	private static final Primitive _JMAKE_INVOCATION_HANDLER =
+	    new Primitive("%jmake-invocation-handler", PACKAGE_JAVA, false,
+	                  "function") {
+		
+	      	public LispObject execute(LispObject[] args) throws ConditionThrowable {
+	      		int length = args.length;
+	      		if (length != 1) {
+	      			return error(new WrongNumberOfArgumentsException(this));
+	      		}
+	      		if(!(args[0] instanceof Function)) {
+	      			return error(new TypeError(args[0], Symbol.FUNCTION));
+	      		}
+	      		
+	      		return new JavaObject(new LispInvocationHandler((Function) args[0]));
+	      	}
+	    };
+
+    private static final Primitive _JMAKE_PROXY =
+	    new Primitive("%jmake-proxy", PACKAGE_JAVA, false,
+	                  "interface invocation-handler") {
+		
+	      	public LispObject execute(final LispObject[] args) throws ConditionThrowable {
+	      		int length = args.length;
+	      		if (length != 2) {
+	      			return error(new WrongNumberOfArgumentsException(this));
+	      		}
+	      		if(!(args[0] instanceof JavaObject) ||
+	      		   !(((JavaObject) args[0]).javaInstance() instanceof Class)) {
+	      			return error(new TypeError(args[0], new SimpleString(Class.class.getName())));
+	      		}
+	      		if(!(args[1] instanceof JavaObject) ||
+ 	      		   !(((JavaObject) args[1]).javaInstance() instanceof InvocationHandler)) {
+	 	      			return error(new TypeError(args[1], new SimpleString(InvocationHandler.class.getName())));
+	 	      		}
+	      		Class<?> iface = (Class<?>) ((JavaObject) args[0]).javaInstance();
+	      		InvocationHandler invocationHandler = (InvocationHandler) ((JavaObject) args[1]).javaInstance(); 
+	      		Object proxy = Proxy.newProxyInstance(
+	      				iface.getClassLoader(),
+	      				new Class[] { iface },
+	      				invocationHandler);
+	      		return new JavaObject(proxy);
+	      	}
+	    };    
+	    
+	private static LispObject toLispObject(Object obj) {
+		return (obj instanceof LispObject) ? (LispObject) obj : new JavaObject(obj);
+	}    
+	    
   	private static final Primitive _JIMPLEMENT_INTERFACE =
 	    new Primitive("%jimplement-interface", PACKAGE_JAVA, false,
 	                  "interface &rest method-names-and-defs") {

Modified: branches/scripting/j/src/org/armedbear/lisp/autoloads.lisp
==============================================================================
--- branches/scripting/j/src/org/armedbear/lisp/autoloads.lisp	(original)
+++ branches/scripting/j/src/org/armedbear/lisp/autoloads.lisp	Thu Oct 30 06:30:25 2008
@@ -189,6 +189,10 @@
 (autoload 'jinterface-implementation "java")
 (export 'jimplement-interface "JAVA")
 (autoload 'jimplement-interface "java")
+(export 'jmake-invocation-handler "JAVA")
+(autoload 'jmake-invocation-handler "java")
+(export 'jmake-proxy "JAVA")
+(autoload 'jmake-proxy "java")
 (export 'jobject-class "JAVA")
 (autoload 'jobject-class "java")
 (export 'jclass-superclass "JAVA")

Modified: branches/scripting/j/src/org/armedbear/lisp/java.lisp
==============================================================================
--- branches/scripting/j/src/org/armedbear/lisp/java.lisp	(original)
+++ branches/scripting/j/src/org/armedbear/lisp/java.lisp	Thu Oct 30 06:30:25 2008
@@ -102,6 +102,15 @@
         (push method-name method-names-and-defs)))
     (apply #'%jimplement-interface interface method-names-and-defs)))
 
+(defun jmake-invocation-handler (function)
+  (%jmake-invocation-handler function))
+
+(defun jmake-proxy (interface invocation-handler)
+  (let ((handler (if (functionp invocation-handler)
+		     (jmake-invocation-handler invocation-handler)
+		     invocation-handler)))
+    (%jmake-proxy (jclass interface) handler)))
+
 (defun jobject-class (obj)
   "Returns the Java class that OBJ belongs to"
   (jcall (jmethod "java.lang.Object" "getClass") obj))

Modified: branches/scripting/j/src/org/armedbear/lisp/scripting/AbclScriptEngine.java
==============================================================================
--- branches/scripting/j/src/org/armedbear/lisp/scripting/AbclScriptEngine.java	(original)
+++ branches/scripting/j/src/org/armedbear/lisp/scripting/AbclScriptEngine.java	Thu Oct 30 06:30:25 2008
@@ -277,11 +277,16 @@
 		try {
 			in = new ReaderInputStream(ctx.getReader());
 			out = new WriterOutputStream(ctx.getWriter());
+			Stream outStream = new Stream(out, Symbol.CHARACTER);
 			retVal = evalScript.execute(makeBindings(ctx.getBindings(ScriptContext.GLOBAL_SCOPE)),
 										makeBindings(ctx.getBindings(ScriptContext.ENGINE_SCOPE)),
 										new Stream(in, Symbol.CHARACTER),
-										new Stream(out, Symbol.CHARACTER),
+										outStream,
 										new SimpleString(code), new JavaObject(ctx));
+			outStream._finishOutput();
+			out.flush();
+			in.close();
+			out.close();
 			return toJava(retVal);
 		} catch (ConditionThrowable e) {
 			throw new ScriptException(new Exception(e));




More information about the armedbear-cvs mailing list