--- /dev/null
+// 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; }
+ }
+
+}
public void changed(Watched w) {
super.changed(w);
+ /*
Log.debug(this, "changed(" + w + ")");
try {
ClassLoader cl = getClassLoader();
Method m = c.getMethod("main", new Class[] { });
m.invoke(null, new Object[] { });
} catch (Exception e) {
- Log.warn(this, "nope");
+ Log.warn(this, e);
}
+ */
}
}
/** 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;
}
}
-
- 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);
}
}
- // 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;
- }
- */
- }
+
}
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); }
}
// 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);
} finally {
conn.close();
}
- } }).start();
+ } });
}
private class PortThread extends Thread {
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);
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);
--- /dev/null
+// 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;
+ }
+
+}
if (kid == null) continue;
cache.put(kids[i], kid);
watcher().changed(kid);
+ kid.scan();
} else {
kid.scan();
}