tons of changes
authoradam <adam@megacz.com>
Fri, 18 Mar 2005 09:11:22 +0000 (09:11 +0000)
committeradam <adam@megacz.com>
Fri, 18 Mar 2005 09:11:22 +0000 (09:11 +0000)
darcs-hash:20050318091122-5007d-b1a8d1b6ece6e776b6a865fff8fb89a2e2245b0f.gz

src/org/ibex/jetty/Jetty.java [new file with mode: 0644]
src/org/ibex/jinetd/Host.java
src/org/ibex/jinetd/Loader.java
src/org/ibex/jinetd/Main.java
src/org/ibex/jinetd/Port.java
src/org/ibex/jinetd/Root.java
src/org/ibex/jinetd/TreeClassLoader.java [new file with mode: 0644]
src/org/ibex/jinetd/Watched.java

diff --git a/src/org/ibex/jetty/Jetty.java b/src/org/ibex/jetty/Jetty.java
new file mode 100644 (file)
index 0000000..b5fa5fe
--- /dev/null
@@ -0,0 +1,130 @@
+// Copyright 2000-2005 the Contributors, as shown in the revision logs.
+// Licensed under the Apache Public Source License 2.0 ("the License").
+// You may not use this file except in compliance with the License.
+
+package org.ibex.jetty;
+import org.mortbay.jetty.servlet.*;
+import org.mortbay.jetty.*;
+import org.mortbay.http.handler.*;
+import org.mortbay.http.*;
+import org.ibex.util.*;
+import org.ibex.jinetd.*;
+import org.ibex.io.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+public class Jetty {
+
+    private static Jetty instance = null;
+    private static Server hs = null;
+    private static SocketListener sl = null;
+
+    public static synchronized Jetty instance() {
+        if (instance != null) return instance;
+        hs = new Server();
+        sl = new SocketListener();
+        hs.addListener(sl);
+        instance = new Jetty();
+        try {
+            ClassLoader cc = Thread.currentThread().getContextClassLoader();
+            Thread.currentThread().setContextClassLoader(Jetty.class.getClassLoader());
+            sl.setHttpServer(hs);
+            addContexts(Root.root + "/host", null);
+            hs.start();
+            Thread.currentThread().setContextClassLoader(cc);
+        } catch (Exception e) { Log.error(Main.class, e); }
+        return instance;
+    }
+
+    private static void addContexts(String path, String host) {
+        try {
+            File webinf = new File(path + "/WEB-INF");
+            if (webinf.exists()) {
+                String pad = "";
+                while(pad.length() + host.length() < 30) pad += " ";
+                try {
+                    InetAddress.getByName(host);
+                    Log.info(Main.class, pad + host + " => " + path);
+                    WebApplicationContext context = hs.addWebApplication(host, "", path);
+                    context.getServletHandler().getHttpContext().setParentClassLoader(Jetty.class.getClassLoader());
+                    context.setClassLoaderJava2Compliant(true);
+                    context.setClassLoader(new TreeClassLoader(webinf, Jetty.class.getClassLoader()));
+                    context.setParentClassLoader(Jetty.class.getClassLoader());
+                    context.setResourceBase(path+"/");
+
+                    ServletHolder sh = context.addServlet("jsp", "*.jsp", "org.apache.jasper.servlet.JspServlet");
+                    sh.setInitParameter("fork", "false");
+                    sh.setInitParameter("mappedfile", "true");
+                    sh.setInitParameter("keepgenerated", "false");
+                    sh.setInitOrder(0);
+
+                    context.setWelcomeFiles(new String[] { "index.jsp", "index.html", "index.xt", "index.txt" });
+                    ServletHolder def = context.addServlet("default", "/", "org.mortbay.jetty.servlet.Default");
+                    def.setInitParameter("acceptRanges", "true");
+                    def.setInitParameter("dirAllowed", "true");
+                    def.setInitParameter("putAllowed", "false");
+                    def.setInitParameter("delAllowed", "false");
+                    def.setInitParameter("redirectWelcome", "false");
+                    def.setInitParameter("minGzipLength", "8192");
+                    def.setInitOrder(0);
+
+                    context.setDefaultsDescriptor(null);
+                    context.addHandler(new ResourceHandler());
+                    context.addHandler(new NotFoundHandler());
+                    context.setWelcomeFiles(new String[] { "index.jsp", "index.html", "index.xt", "index.txt" });
+
+                } catch (UnknownHostException e) {
+                    Log.warn(Main.class, pad + host + " => " + e.getClass().getName());
+                }
+                //return;
+            }
+            File f = new File(path);
+            if (!f.isDirectory()) return;
+            String[] list = f.list();
+            for(int i=0; i<list.length; i++) {
+                if (list[i].indexOf('.') != -1) continue;
+                if (!list[i].toLowerCase().equals(list[i])) continue;
+                addContexts(path + File.separatorChar + list[i], (host == null ? list[i] : (list[i] + "." + host)));
+            }
+        } catch (Exception e) {
+            Log.warn(Main.class, e);
+        }
+    }
+
+    public void accept(Connection conn) {
+        try {
+            try { sl.handleConnection(conn.getSocket()); } finally { conn.close(); }
+        } catch (Exception e) {
+            Log.error(this, e);
+            if (e instanceof javax.servlet.ServletException) Log.error(this, ((javax.servlet.ServletException)e).getRootCause());
+        }
+    }
+
+
+    // Logging //////////////////////////////////////////////////////////////////////////////
+
+    static { System.setProperty("org.apache.commons.logging.Log", "org.ibex.jetty.Jetty$LogAdapter"); }
+    public static class LogAdapter implements org.apache.commons.logging.Log {
+        public LogAdapter(String s) { }
+        public void trace(Object o)              { /* Log.debug("[jetty]", o); */ }
+        public void trace(Object o, Throwable t) { /* Log.debug("[jetty]", o); Log.debug("[jetty]", t); */ }
+        public void debug(Object o)              { /* Log.debug("[jetty]", o); */ }
+        public void debug(Object o, Throwable t) { /* Log.debug("[jetty]", o); Log.debug("[jetty]", t); */ }
+        public void info(Object o)               { /* Log.info("[jetty]", o); */ }
+        public void info(Object o, Throwable t)  { /* Log.info("[jetty]", o); Log.info("[jetty]", t); */ }
+        public void warn(Object o)               { Log.warn("[jetty]", o); }
+        public void warn(Object o, Throwable t)  { Log.warn("[jetty]", o); Log.warn("[jetty]", t); }
+        public void error(Object o)              { Log.error("[jetty]", o); }
+        public void error(Object o, Throwable t) { Log.error("[jetty]", o); Log.error("[jetty]", t); }
+        public void fatal(Object o)              { Log.error("[jetty]", o); }
+        public void fatal(Object o, Throwable t) { Log.error("[jetty]", o); Log.error("[jetty]", t); }
+        public boolean isTraceEnabled()          { return false; }
+        public boolean isDebugEnabled()          { return false; }
+        public boolean isInfoEnabled()           { return false; }
+        public boolean isWarnEnabled()           { return true; }
+        public boolean isErrorEnabled()          { return true; }
+        public boolean isFatalEnabled()          { return true; }
+    }
+
+}
index a5c3923..1b10beb 100644 (file)
@@ -15,6 +15,7 @@ public class Host extends Loader {
 
     public void changed(Watched w) {
         super.changed(w);
+        /*
         Log.debug(this, "changed(" + w + ")");
         try {
             ClassLoader cl = getClassLoader();
@@ -24,7 +25,8 @@ public class Host extends Loader {
             Method m = c.getMethod("main", new Class[] { });
             m.invoke(null, new Object[] { });
         } catch (Exception e) {
-            Log.warn(this, "nope");
+            Log.warn(this, e);
         }
+        */
     }
 }
index 012a935..7f32fd6 100644 (file)
@@ -14,39 +14,13 @@ import java.util.zip.*;
 /** represents a file or directory which is scanned for updates */
 public class Loader extends Watcher {
 
-    ClassLoader parentClassLoader = null;
-    static final ClassLoader mycl = Loader.class.getClassLoader();
+    public /*synchronized*/ void scan() throws IOException { super.scan(); }
 
-    protected ThreadGroup tg = new ThreadGroup(getAbsolutePath());
-
-    public Loader(String path) { super(path); }
-    //public Loader(String path, ClassLoader pcl) { super(path); this.parentClassLoader = pcl; }
-    
-    private TreeClassLoader classloader = null;
-    public synchronized void scan() throws IOException { super.scan(); }
-    public synchronized ClassLoader getClassLoader() {
-        ClassLoader classloader = this.classloader;
-        if (classloader == null) {
-            String s = getClassPath();
-            StringTokenizer st = new StringTokenizer(s, File.pathSeparatorChar+"");
-            URL[] urls = new URL[st.countTokens()];
-            try {
-                for(int i=0; i<urls.length; i++) {
-                    String us = st.nextToken();
-                    //if (us.endsWith(".jar")) us = "jar:file:"+us+"!/";
-                    if (us.endsWith(".jar")) us = "file:"+us;
-                    else us = "file:"+us+"/";
-                    urls[i] = new URL(us);
-                }
-            } catch (MalformedURLException e) {
-                Log.error(this, e);
-                return null;
-            }
-            classloader = this.classloader = new TreeClassLoader(urls/*, parentClassLoader*/);
-            try { compileSource(); } catch (Exception e) { Log.error(this, e); }
-        }
-        return classloader;
-    }
+    private final TreeClassLoader classloader;
+    public synchronized ClassLoader getClassLoader() { return classloader; }
+    public Loader(String path) { this(path, Loader.class.getClassLoader()); }
+    public Loader(String path, ClassLoader parent) { super(path); classloader = new TreeClassLoader(this, parent); }
+    public void changed(Watched w) { /*FIXME*/ }
 
     private void fill(Vec vec, File dir) {
         if (!dir.exists()) return;
@@ -60,98 +34,7 @@ public class Loader extends Watcher {
         }
     }
 
-
-    public String getClassPath() {
-        String classpath = System.getProperty("java.class.path");
-        String [] l = new File(Root.root + "/LIB/").list();
-        for(int i=0; l != null && i<l.length; i++) {
-            if (!l[i].endsWith(".jar")) continue;
-            classpath += File.pathSeparatorChar;
-            classpath += Root.root + "/LIB/" + l[i];
-        }
-        l = new File(this.path + File.separatorChar + "LIB").list();
-        for(int i=0; l!=null && i<l.length; i++) {
-            if (!l[i].endsWith(".jar")) continue;
-            classpath += File.pathSeparatorChar;
-            classpath += this.path + "/LIB/" + l[i];
-        }
-        return classpath + File.pathSeparatorChar + this.path + "/BIN";
-    }
-
-    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();
-            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("-classpath");
-            args.addElement(getClassPath());
-            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");
-        }
-        */
-
-            File bindir = new File(this.path + File.separatorChar + "BIN");  bindir.mkdirs();
-            Vec args = new Vec();
-            args.addElement("/usr/bin/javac");
-            args.addElement("-nowarn");
-            args.addElement("-classpath");
-            args.addElement(getClassPath());
-            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 javac for " + srcdir.getAbsolutePath());
-            final Process javac = Runtime.getRuntime().exec(all, new String[] { "PATH=/bin:/usr/bin" });
-            final BufferedReader out = new BufferedReader(new InputStreamReader(javac.getInputStream()));
-            final BufferedReader err = new BufferedReader(new InputStreamReader(javac.getErrorStream()));
-            new Thread() { public void run() {
-                try { for(String s = out.readLine(); s != null; s = out.readLine()) Log.info("javac [stdout]", s); }
-                catch (Exception e) { Log.warn("javac", e); } } }.start();
-            new Thread() { public void run() {
-                try { for(String s = err.readLine(); s != null; s = err.readLine()) Log.info("javac [stderr]", s); }
-                catch (Exception e) { Log.warn("javac", e); } } }.start();
-            javac.waitFor();
-
-    }
-
-    // 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; }
-
-
+    protected ThreadGroup tg = new ThreadGroup(getAbsolutePath());
     private void nuke() {
         if (tg.activeCount() == 0) return;
         Log.info(this, "killing all threads for: " + path);
@@ -177,87 +60,5 @@ public class Loader extends Watcher {
         }
     }
 
-    // dump the classloader if anything changes
-    public void changed(Watched w) {
-        if (w.path.indexOf("BIN") != -1) return;
-        if (classloader != null) {
-            for(int i=0; i<3; i++) nuke();
-            tg = new ThreadGroup(getAbsolutePath());
-            Log.info(this, "scheduling classes for reload due to change in: " + w.path);
-            classloader = null;
-        }
-    }
-    
-    public class TreeClassLoader extends java.net.URLClassLoader {
-
-        public String getClassPath() { return Loader.this.getClassPath(); }
-
-        public TreeClassLoader(java.net.URL[] urls) { super(urls); }
-        //private Hashtable cache = new Hashtable();
-        /*
-        public InputStream getResourceAsStream(String name) { return getInputStream(name); }
-
-        private synchronized Class defineClass(String name) {
-            try {
-                InputStream is = null;
-                byte[] b = null;
-                try {
-                    is = getInputStream(name.replace('.', File.separatorChar) + ".class");
-                    if (is == null) return null;
-                    b = InputStreamToByteArray.convert(is);
-                } finally { if (is != null) is.close(); }
-                return defineClass(b, 0, b.length);
-            } catch (Exception e) {
-                Log.error(this, e);
-                return null;
-            }
-        }
-
-        private InputStream getInputStream(String name) {
-            // first see if it's just sitting there
-            File classFile = slash("BIN").slash(name);
-            if (classFile.exists()) try {
-                return new FileInputStream(classFile);
-            } catch (Exception e) { Log.warn(this, e); }
-
-            // then scan the jarfiles for it
-            File lib = slash("LIB");
-            if (lib.exists() && lib.isDirectory()) try {
-                boolean first = true;
-                while(true) {
-                    String[] paths = first ? lib.list() : 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() + " for " + name);
-                            ZipFile zf = new ZipFile(f);
-                            ZipEntry ze = zf.getEntry(name);
-                            if (ze != null) return zf.getInputStream(ze);
-                            zf.close();
-                        }
-                    }
-                    if (!first) break;
-                    first = false;
-                }
-            } 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 {
-            Class c = (Class)cache.get(name);
-            if (c == null) try { c = findSystemClass(name); } catch (ClassNotFoundException cfe) { }
-            if (c == null) try { c = Class.forName(name); } catch (ClassNotFoundException cfe) { }
-            if (c == null) c = defineClass(name);
-            if (c == null) throw new ClassNotFoundException();
-            cache.put(name, c);
-            if (resolve) resolveClass(c);
-            return c;
-        }
-        */
-    }
+   
 }
index ca18381..e45c6c3 100644 (file)
@@ -66,8 +66,8 @@ public class Main {
         Log.color = true;
         Root root = new Root(Root.root);
         while(true) try {
-            Thread.sleep(1000);
-            if (root != null) root.scan();
+            if (root != null) { root.scan(); return; }
+            Thread.sleep(100);
         } catch (Exception e) { Log.error(Main.class, e); }
     }
 
index 8a92dd7..b4d1039 100644 (file)
@@ -14,93 +14,39 @@ import java.util.zip.*;
 // Feature: port-level redirects
 public class Port extends Loader {
 
+    final ThreadPool tp;
     final InetAddress bindTo;
     final int port;
 
     private static Hash cache = new Hash();
-    public static Port newPort(String path, InetAddress bindTo, int port) throws IOException {
+    public static Port newPort(String path, InetAddress bindTo, int port, ThreadPool tp) throws IOException {
         String canonical = new File(path).getCanonicalPath();
         Port p = (Port)cache.get(canonical);
-        if (p == null) cache.put(canonical, p = new Port(path, bindTo, port));
+        if (p == null) cache.put(canonical, p = new Port(path, bindTo, port, tp));
         else Log.warn(Port.class, "   sharing " + bindTo+":"+port+" -> "+ (p.bindTo+":"+p.port));
         p.spawn(bindTo, port);
         return p;
     }
 
     void spawn(InetAddress bindTo, int port) { new PortThread(bindTo, port).start(); }
-    private Port(String path, InetAddress bindTo, int port) {
-        super(path);
-        this.bindTo = bindTo;
-        this.port = port;
-    }
+    private Port(String path, InetAddress bindTo, int port, ThreadPool tp) { 
+        super(path); this.bindTo = bindTo; this.port = port; this.tp = tp; }
 
     public void changed(Watched w) {
         //Log.warn(this, "Port: noticed change in " + w);
         super.changed(w);
     }
 
-
-    Class isListener(String name) throws ClassNotFoundException {
-        final ClassLoader cl = getClassLoader();
-        final Class c = cl.loadClass(name);
-        if (c == null) return null;
-        if (Listener.class.isAssignableFrom(c) && c != Listener.class) return c;
-        return null;
-    }
-
-    Class findListener() throws Exception {
-        getClassLoader();
-        String[] list = list();
-        for(int i=0; i<list.length; i++) {
-            if (!list[i].endsWith(".jar")) continue;
-            //Log.warn(this, "checking " + (this.path + File.separatorChar + list[i]));
-            File f = new File(this.path + File.separatorChar + list[i]);
-            FileInputStream fis = null;
-            try {
-                fis = new FileInputStream(f);
-                ZipInputStream zis = new ZipInputStream(fis);
-                for(ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry()) {
-                    String name = ze.getName();
-                    if (name.endsWith(".class")) {
-                        String classname = name.substring(0, name.length() - ".class".length()).replace('/', '.');
-                        Class c = isListener(classname);
-                        if (c != null) return c;
-                    }
-                }
-            } finally { if (fis != null) fis.close(); }
-        }
-        return findListener(new File(getAbsolutePath() + File.separatorChar + "BIN"));
-    }
-
-    Class findListener(File f) throws Exception {
-        if (!f.exists()) return null;
-        if (!f.isDirectory()) {
-            if (!f.getAbsolutePath().endsWith(".class")) return null;
-            String name = f.getAbsolutePath().substring(getAbsolutePath().length() + 5);
-            name = name.substring(0, name.length() - ".class".length()).replace(File.separatorChar, '.');
-            Class c = isListener(name);
-            if (c != null) return c;
-        } else {
-            String[] list = f.list();
-            for(int i=0; i<list.length; i++) {
-                String classname = f.getAbsolutePath() + File.separatorChar + list[i];
-                Class c = findListener(new File(classname));
-                if (c != null) return c;
-            }
-        }
-        return null;
-    }
-
     void dispatch(final Connection conn) throws Exception {
-        new Thread(tg, new Runnable() { public void run() {
+        tp.appendTask(new Runnable() { public void run() {
             String local = conn.getLocalAddress() + ":" + conn.getLocalPort();
             String remote = conn.getRemoteHostname() + ":" + conn.getRemotePort();
             try {
-                Class c = findListener();
+                final ClassLoader cl = getClassLoader();
+                Class c = cl.loadClass("org.ibex.mail.Main");
                 if (c == null) throw new RuntimeException("couldn't find listener");
                 Log.info("["+local+"]", "connection from " + remote + " => " + c.getName());
                 Log.clearnotes();
-                final ClassLoader cl = getClassLoader();
                 Thread.currentThread().setContextClassLoader(cl);
                 Listener l = (Listener)c.newInstance();
                 l.accept(conn);
@@ -113,7 +59,7 @@ public class Port extends Loader {
             } finally {
                 conn.close();
             }
-        } }).start();
+        } });
     }
 
     private class PortThread extends Thread {
index d89b04c..49bcf39 100644 (file)
@@ -11,9 +11,12 @@ import java.net.*;
 public class Root extends Loader {
 
     public static String root = System.getProperty("jinetd.root", null);
+
     private final Host host;
     private final Watched port;
 
+    private static final ThreadPool tp = new ThreadPool(10, 100);
+
     public Root(String path) {
         super(path);
         host = new Host(path + File.separatorChar + "host", null);
@@ -56,7 +59,8 @@ public class Root extends Loader {
             try {
                 return Port.newPort(this.path + File.separatorChar + part,
                                     ipaddr == null ? null : InetAddress.getByName(ipaddr),
-                                    portnum.equals("*") ? 0 : Integer.parseInt(portnum));
+                                    portnum.equals("*") ? 0 : Integer.parseInt(portnum),
+                                    tp);
             } catch (UnknownHostException e) {  Log.warn(this, "can't resolve host for port directory: " + part);
             } catch (NumberFormatException e) { Log.warn(this, "invalid port directory: " + part);
             } catch (Exception e) {             Log.warn(this, "error instantiating Port: " + part);
diff --git a/src/org/ibex/jinetd/TreeClassLoader.java b/src/org/ibex/jinetd/TreeClassLoader.java
new file mode 100644 (file)
index 0000000..e9f901f
--- /dev/null
@@ -0,0 +1,115 @@
+// Copyright 2000-2005 the Contributors, as shown in the revision logs.
+// Licensed under the Apache Public Source License 2.0 ("the License").
+// You may not use this file except in compliance with the License.
+
+package org.ibex.jinetd;
+import org.ibex.io.*;
+import org.ibex.util.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.net.*;
+import java.util.zip.*;
+
+public class TreeClassLoader extends URLClassLoader {
+
+    private final File root;
+    private final File lib;
+    private Hashtable cache = new Hashtable();
+
+    public TreeClassLoader(File root, ClassLoader parent) {
+        super(new URL[] { }, parent);
+        this.root = root;
+        this.lib = new File(root.getAbsolutePath() + File.separatorChar + "lib");
+    }
+
+    // Classloading //////////////////////////////////////////////////////////////////////////////
+
+    public URL[] getURLs() {
+        try {
+            Vec v = new Vec();
+            if (getParent() != null && getParent() instanceof URLClassLoader) {
+                URL[] parentUrls = ((URLClassLoader)getParent()).getURLs();
+                for(int i=0; i<parentUrls.length; i++) v.addElement(parentUrls[i]);
+            }
+            String vmClasspath =
+                System.getProperty("java.class.path") +
+                File.pathSeparatorChar +
+                System.getProperty("sun.boot.class.path");
+            StringTokenizer st = new StringTokenizer(vmClasspath, File.pathSeparatorChar+"");
+            while(st.hasMoreTokens()) v.addElement(new URL("file:" + st.nextToken()));
+            v.addElement(new URL("file:" + root.getAbsolutePath()));
+            v.addElement(new URL("file:" + root.getAbsolutePath() + File.separatorChar + "classes"));
+            for(Enumeration e = enumerateJarFiles(); e.hasMoreElements(); )
+                v.addElement(new URL("file:" + ((File)e.nextElement()).getAbsolutePath()));
+            return (URL[])v.copyInto(new URL[v.size()]);
+        } catch (MalformedURLException e) {
+            Log.error(this, e);
+            return null;
+        }
+    }
+
+    private synchronized Class defineClass(String name) throws ClassNotFoundException {
+        InputStream is = null;
+        try {
+            is = getClassInputStream(name);
+            if (is == null) return null;
+            byte[] b = InputStreamToByteArray.convert(is);
+            Class ret = defineClass(b, 0, b.length);
+            cache.put(name, ret);
+            return ret;
+        } catch (Exception e) {
+            Log.error(this, e);
+            throw new ClassNotFoundException();
+        } finally {
+            if (is != null) try { is.close(); } catch (Exception e) { Log.error(this, e); }
+        }
+    }
+
+    public synchronized Class findClass(String name) throws ClassNotFoundException {
+        Class c = (Class)cache.get(name);
+        if (c==null) c = defineClass(name);
+        if (c==null) throw new ClassNotFoundException(name);
+        return c;
+    }
+
+    // Filesystem Methods //////////////////////////////////////////////////////////////////////////////
+
+    private static final FilenameFilter jarFilter =
+        new FilenameFilter() { public boolean accept(File f, String s) {return s.endsWith(".jar");}};
+    public Enumeration enumerateJarFiles() {
+        Enumeration rootJars =
+            new Misc.ArrayEnumeration(root.list(jarFilter)) {
+                public Object nextElement() { return new File(root.getAbsolutePath()+File.separatorChar+super.nextElement()); } };
+        Enumeration libJars =
+            new Misc.ArrayEnumeration(lib.list(jarFilter)) {
+                public Object nextElement() { return new File(lib.getAbsolutePath()+File.separatorChar+super.nextElement()); } };
+        return new Misc.JoinEnumeration(rootJars, libJars);
+    }
+
+    public InputStream getResourceAsStream(String name) {
+        InputStream ret = getInputStream(name);
+        if (ret == null) ret = getParent().getResourceAsStream(name);
+        return ret;
+    }
+
+    public InputStream getClassInputStream(String classname) { return getInputStream(classname.replace('.', '/')+".class"); }
+    public InputStream getInputStream(String name) {
+        try {
+            File f = new File(root.getAbsolutePath() + File.separatorChar + name);
+            if (f.exists()) return new FileInputStream(f);
+        } catch (IOException e) { /* DELIBERATE */ }
+        try {
+            File f = new File("classes" + File.separatorChar + root.getAbsolutePath() + File.separatorChar + name);
+            if (f.exists()) return new FileInputStream(f);
+        } catch (IOException e) { /* DELIBERATE */ }
+        for(Enumeration e = enumerateJarFiles(); e.hasMoreElements();) try {
+            ZipFile zf = new ZipFile((File)e.nextElement());
+            ZipEntry ze = zf.getEntry(name);
+            if (ze != null) return zf.getInputStream(ze);
+            zf.close();
+        } catch (Exception ex) { Log.warn(this, ex); }
+        return null;
+    }
+
+}
index 50a7bc2..332c0f4 100644 (file)
@@ -38,6 +38,7 @@ public class Watched extends File {
                 if (kid == null) continue;
                 cache.put(kids[i], kid);
                 watcher().changed(kid);
+                kid.scan();
             } else {
                 kid.scan();
             }