+package org.ibex.jinetd;
+import org.ibex.util.*;
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+/** represents a file or directory which is scanned for updates */
+public class Loader extends Watcher {
+
+ public Loader(String path) { super(path); }
+
+ private TreeClassLoader classloader = new TreeClassLoader();
+ public ClassLoader getClassLoader() {
+ ClassLoader classloader = this.classloader;
+ if (classloader == null) {
+ classloader = this.classloader = new TreeClassLoader();
+ Log.warn(this, "getting classloader...");
+ try {
+ compileSource();
+ } catch (Exception e) {
+ Log.error(this, e);
+ }
+ }
+ return classloader;
+ }
+
+ private void fill(Vec vec, File dir) {
+ if (!dir.exists()) return;
+ if (!dir.isDirectory()) {
+ if (!dir.getPath().endsWith(".java")) return;
+ vec.addElement(dir.getAbsolutePath());
+ } else {
+ String[] list = dir.list();
+ for(int i=0; i<list.length; i++)
+ fill(vec, new File(dir.getAbsolutePath() + File.separatorChar + list[i]));
+ }
+ }
+ private void compileSource() throws Exception {
+ File srcdir = new File(this.path + File.separatorChar + "SRC");
+ if (!srcdir.exists()) return;
+ if (new File("/usr/bin/jikes").exists()) {
+ File bindir = new File(this.path + File.separatorChar + "BIN"); bindir.mkdirs();
+ File libdir = new File(this.path + File.separatorChar + "LIB");
+ String classpath = System.getProperty("java.class.path");
+ String [] l = new File("/jinetd/LIB/").list();
+ for(int i=0; i<l.length; i++) {
+ if (!l[i].endsWith(".jar")) continue;
+ classpath += File.pathSeparatorChar;
+ classpath += "/jinetd/LIB/" + l[i];
+ }
+ String bootclasspath = System.getProperty("sun.boot.class.path", "");
+ Vec args = new Vec();
+ args.addElement("/usr/bin/jikes");
+ args.addElement("+E");
+ args.addElement("-nowarn");
+ args.addElement("-bootclasspath");
+ args.addElement(bootclasspath);
+ args.addElement("-extdirs");
+ args.addElement(libdir.getAbsolutePath());
+ args.addElement("-classpath");
+ args.addElement(classpath);
+ args.addElement("-sourcepath");
+ args.addElement(srcdir.getAbsolutePath());
+ args.addElement("-d");
+ args.addElement(bindir.getAbsolutePath());
+ fill(args, srcdir);
+ String[] all = new String[args.size()];
+ args.copyInto(all);
+ Log.info(this, "invoking jikes");
+ for(int i=0; i<all.length; i++) Log.info(this, " " + all[i]);
+ final Process jikes = Runtime.getRuntime().exec(all);
+ final BufferedReader out = new BufferedReader(new InputStreamReader(jikes.getInputStream()));
+ final BufferedReader err = new BufferedReader(new InputStreamReader(jikes.getErrorStream()));
+ new Thread() { public void run() {
+ try { for(String s = out.readLine(); s != null; s = out.readLine()) Log.info("jikes[stdout]", s); }
+ catch (Exception e) { Log.warn("jikes", e); } } }.start();
+ new Thread() { public void run() {
+ try { for(String s = err.readLine(); s != null; s = err.readLine()) Log.info("jikes[stderr]", s); }
+ catch (Exception e) { Log.warn("jikes", e); } } }.start();
+ jikes.waitFor();
+ } else {
+ Log.error(this, "ACK! jikes not found, javac not (yet) supported");
+ }
+ }
+
+ // only watch SRC and LIB for changes
+ public Watched slash(String path) {
+ return (path.equals("LIB") ||
+ path.equals("BIN") ||
+ path.equals("SRC") ||
+ path.endsWith(".jar") ) ? super.slash(path) : null; }
+
+
+ // dump the classloader if anything changes
+ public void changed(Watched w) {
+ if (w.path.indexOf("BIN") != -1) return;
+ if (classloader != null) {
+ Log.info(this, "Reloading all classes: " + path);
+ classloader = null;
+ }
+ }
+
+ private class TreeClassLoader extends ClassLoader {
+ private Hashtable cache = new Hashtable();
+
+ private synchronized Class defineClass(String name) {
+ // first see if it's just sitting there
+ File classFile = slash("BIN").slash(name.replace('.', File.separatorChar) + ".class");
+ if (classFile.exists()) {
+ try {
+ FileInputStream fis = new FileInputStream(classFile);
+ byte[] b = InputStreamToByteArray.convert(fis);
+ fis.close();
+ Log.debug(this, " loading " + name + " from " + classFile.getAbsolutePath());
+ return defineClass(b, 0, b.length);
+ } catch (Exception e) {
+ Log.warn(this, e);
+ }
+ }
+
+ // then scan the jarfiles for it
+ File lib = slash("LIB");
+ if (lib.exists() && lib.isDirectory()) {
+ try {
+ String[] paths = lib.list();
+ for(int i=0; i<paths.length; i++) {
+ if (paths[i].endsWith(".jar")) {
+ File f = new File(getAbsolutePath()+File.separatorChar+"LIB"+File.separatorChar+paths[i]);
+ //Log.debug(this, " scanning " + f.getAbsolutePath());
+ ZipFile zf = new ZipFile(f);
+ ZipEntry ze = zf.getEntry(name.replace('.', File.separatorChar) + ".class");
+ if (ze != null) {
+ byte[] b = InputStreamToByteArray.convert(zf.getInputStream(ze));
+ Log.debug(this, " loading " + name + " from " + f.getAbsolutePath());
+ zf.close();
+ return defineClass(b, 0, b.length);
+ }
+ zf.close();
+ }
+ }
+ } catch (Exception e) {
+ Log.warn(this, e);
+ }
+
+ // finally scan ourselves
+ try {
+ String[] paths = list();
+ for(int i=0; i<paths.length; i++) {
+ if (paths[i].endsWith(".jar")) {
+ File f = new File(getAbsolutePath()+File.separatorChar+paths[i]);
+ //Log.debug(this, " scanning " + f.getAbsolutePath());
+ ZipFile zf = new ZipFile(f);
+ ZipEntry ze = zf.getEntry(name.replace('.', File.separatorChar) + ".class");
+ if (ze != null) {
+ byte[] b = InputStreamToByteArray.convert(zf.getInputStream(ze));
+ Log.debug(this, " loading " + name + " from " + f.getAbsolutePath());
+ zf.close();
+ return defineClass(b, 0, b.length);
+ }
+ zf.close();
+ }
+ }
+ } catch (Exception e) {
+ Log.warn(this, e);
+ }
+
+ }
+
+ // finally, resort to compiling it if we have to
+ //File src = new File(getAbsolutePath() + File.separatorChar + "SRC");
+ // FIXME
+ //if (!sourcebuilt) buildSource();
+ return null;
+ }
+
+ public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ try {
+ Class c = findSystemClass(name);
+ if (c != null) { if (resolve) resolveClass(c); return c; }
+ } catch (ClassNotFoundException e) { /* DELIBERATE */ }
+ Class c = (Class)cache.get(name);
+ if (c == null) {
+ //Log.info(this, "looking for class " + name);
+ c = defineClass(name);
+ if (c == null) throw new ClassNotFoundException();
+ cache.put(name, c);
+ }
+ if (resolve) resolveClass(c);
+ return c;
+ }
+ }
+}