changeset 1842:22f73129eb4a

add load_jar
author Franklin Schmidt <fschmidt@gmail.com>
date Sat, 01 Feb 2025 16:54:41 -0700
parents 08d650b31a80
children 833096ee8c89
files src/goodjava/io/FileClassLoader.java src/luan/Luan.java src/luan/modules/IoLuan.java src/luan/modules/JavaLuan.java src/luan/modules/Package.luan src/luan/modules/PackageLuan.java
diffstat 6 files changed, 113 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
diff -r 08d650b31a80 -r 22f73129eb4a src/goodjava/io/FileClassLoader.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/goodjava/io/FileClassLoader.java	Sat Feb 01 16:54:41 2025 -0700
@@ -0,0 +1,73 @@
+package goodjava.io;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.MalformedURLException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+
+
+public class FileClassLoader extends URLClassLoader {
+
+	public static final class FileInfo {
+		public final File file;
+		private final long checksum;
+
+		public FileInfo(File file) throws IOException {
+			this.file = file;
+			this.checksum = IoUtils.checksum( new BufferedInputStream( new FileInputStream(file) ) );
+		}
+
+		public boolean equals(Object obj) {
+			if( !(obj instanceof FileInfo) )
+				return false;
+			FileInfo fi = (FileInfo)obj;
+			return this.checksum==fi.checksum && this.file.getName().equals(fi.file.getName());
+		}
+
+		public int hashCode() {
+			return (int)checksum;
+		}
+	}
+
+	private static URL[] toURLs(List<FileInfo> files) {
+		int n = files.size();
+		URL[] urls = new URL[n];
+		for( int i=0; i<n; i++ ) {
+			try {
+				urls[i] = files.get(i).file.toURI().toURL();
+			} catch(MalformedURLException e) {
+				throw new RuntimeException(e);
+			}
+		}
+		return urls;
+	}
+
+	private final List<FileInfo> files;
+
+	private FileClassLoader(List<FileInfo> files) {
+		super(toURLs(files));
+		this.files = new ArrayList<FileInfo>(files);
+	}
+
+	public List<FileInfo> getFiles() {
+		return new ArrayList<FileInfo>(files);
+	}
+
+	private static final Map<List<FileInfo>,FileClassLoader> map = new HashMap<List<FileInfo>,FileClassLoader>();
+
+	public static synchronized FileClassLoader getFileClassLoader(List<FileInfo> files) {
+		FileClassLoader fcl = map.get(files);
+		if( fcl == null ) {
+			fcl = new FileClassLoader(files);
+			map.put(fcl.files,fcl);
+		}
+		return fcl;
+	}
+}
diff -r 08d650b31a80 -r 22f73129eb4a src/luan/Luan.java
--- a/src/luan/Luan.java	Thu Jan 30 20:55:05 2025 -0700
+++ b/src/luan/Luan.java	Sat Feb 01 16:54:41 2025 -0700
@@ -1,6 +1,7 @@
 package luan;
 
 import java.lang.reflect.Array;
+import java.io.File;
 import java.io.IOException;
 import java.util.List;
 import java.util.ArrayList;
@@ -11,7 +12,9 @@
 import java.util.Arrays;
 import java.util.Set;
 import java.util.Collection;
+import java.util.Collections;
 import javax.tools.ToolProvider;
+import goodjava.io.FileClassLoader;
 import goodjava.logging.Logger;
 import goodjava.logging.LoggerFactory;
 import luan.modules.JavaLuan;
@@ -23,18 +26,22 @@
 
 public final class Luan {
 	private static final Logger logger = LoggerFactory.getLogger(Luan.class);
+	private static final FileClassLoader emptyClassLoader = FileClassLoader.getFileClassLoader( Collections.emptyList() );
 
 	private final List<LuanClosure> stack = new ArrayList<LuanClosure>();
 	private final Map registry;
 	private final Map localOnly = new HashMap();
+	private FileClassLoader classLoader;
 
 	public Luan() {
-		registry = new HashMap();
+		this.registry = new HashMap();
+		this.classLoader = emptyClassLoader;
 	}
 
 	public Luan(Luan luan) {
 		LuanMutable.makeImmutable(luan.registry);
 		this.registry = clone(luan.registry);
+		this.classLoader = luan.classLoader;
 	}
 
 	private static Object[] clone(Object[] obj) {
@@ -475,4 +482,20 @@
 		return (Security)luan.registry().put(SECURITY_KEY,s);
 	}
 
+
+	// jars
+
+	public ClassLoader getClassLoader() {
+		return classLoader;
+	}
+
+	public void addJar(File jar) throws IOException {
+		FileClassLoader.FileInfo file = new FileClassLoader.FileInfo(jar);
+		List<FileClassLoader.FileInfo> files = classLoader.getFiles();
+		if( files.contains(file) )
+			return;
+		files.add(file);
+		classLoader = FileClassLoader.getFileClassLoader(files);
+	}
+
 }
diff -r 08d650b31a80 -r 22f73129eb4a src/luan/modules/IoLuan.java
--- a/src/luan/modules/IoLuan.java	Thu Jan 30 20:55:05 2025 -0700
+++ b/src/luan/modules/IoLuan.java	Sat Feb 01 16:54:41 2025 -0700
@@ -136,7 +136,7 @@
 	}
 
 
-	private static File objToFile(Luan luan,Object obj) throws LuanException {
+	static File objToFile(Luan luan,Object obj) throws LuanException {
 		if( obj instanceof String ) {
 			String fileName = (String)obj;
 			check(luan,"file:"+fileName);
diff -r 08d650b31a80 -r 22f73129eb4a src/luan/modules/JavaLuan.java
--- a/src/luan/modules/JavaLuan.java	Thu Jan 30 20:55:05 2025 -0700
+++ b/src/luan/modules/JavaLuan.java	Sat Feb 01 16:54:41 2025 -0700
@@ -347,7 +347,11 @@
 			try {
 				cls = Thread.currentThread().getContextClassLoader().loadClass(name);
 			} catch(ClassNotFoundException e2) {
-				return null;
+				try {
+					cls = luan.getClassLoader().loadClass(name);
+				} catch(ClassNotFoundException e3) {
+					return null;
+				}
 			}
 		}
 		return new Static(cls);
diff -r 08d650b31a80 -r 22f73129eb4a src/luan/modules/Package.luan
--- a/src/luan/modules/Package.luan	Thu Jan 30 20:55:05 2025 -0700
+++ b/src/luan/modules/Package.luan	Sat Feb 01 16:54:41 2025 -0700
@@ -6,6 +6,7 @@
 local Package = {}
 
 Package.load = PackageLuan.load
+Package.load_jar = PackageLuan.load_jar
 
 local loaded = PackageLuan.loaded  -- returns java map
 local mt = {}
diff -r 08d650b31a80 -r 22f73129eb4a src/luan/modules/PackageLuan.java
--- a/src/luan/modules/PackageLuan.java	Thu Jan 30 20:55:05 2025 -0700
+++ b/src/luan/modules/PackageLuan.java	Sat Feb 01 16:54:41 2025 -0700
@@ -2,6 +2,7 @@
 
 import java.io.Reader;
 import java.io.InputStreamReader;
+import java.io.File;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collections;
@@ -113,4 +114,12 @@
 		}
 	}
 
+	public static void load_jar(Luan luan,Object jar) throws LuanException, IOException {
+		Luan.checkSecurity(luan,"java");
+		File file = IoLuan.objToFile(luan,jar);
+		if( file==null )
+			throw new LuanException( "bad argument #1 to 'load_jar' (string or file table expected)" );
+		luan.addJar(file);
+	}
+
 }