1 package org.ibex.jinetd;
2 import org.ibex.util.*;
7 import java.util.zip.*;
9 /** represents a file or directory which is scanned for updates */
10 public class Loader extends Watcher {
12 ClassLoader parentClassLoader = null;
13 static final ClassLoader mycl = Loader.class.getClassLoader();
15 protected ThreadGroup tg = new ThreadGroup(getAbsolutePath());
17 public Loader(String path) { super(path); }
18 //public Loader(String path, ClassLoader pcl) { super(path); this.parentClassLoader = pcl; }
20 private TreeClassLoader classloader = null;
21 public synchronized void scan() throws IOException { super.scan(); }
22 public synchronized ClassLoader getClassLoader() {
23 ClassLoader classloader = this.classloader;
24 if (classloader == null) {
25 String s = getClassPath();
26 StringTokenizer st = new StringTokenizer(s, File.pathSeparatorChar+"");
27 URL[] urls = new URL[st.countTokens()];
29 for(int i=0; i<urls.length; i++) {
30 String us = st.nextToken();
31 //if (us.endsWith(".jar")) us = "jar:file:"+us+"!/";
32 if (us.endsWith(".jar")) us = "file:"+us;
33 else us = "file:"+us+"/";
34 urls[i] = new URL(us);
36 } catch (MalformedURLException e) {
40 classloader = this.classloader = new TreeClassLoader(urls/*, parentClassLoader*/);
41 try { compileSource(); } catch (Exception e) { Log.error(this, e); }
46 private void fill(Vec vec, File dir) {
47 if (!dir.exists()) return;
48 if (!dir.isDirectory()) {
49 if (!dir.getPath().endsWith(".java")) return;
50 vec.addElement(dir.getAbsolutePath());
52 String[] list = dir.list();
53 for(int i=0; i<list.length; i++)
54 fill(vec, new File(dir.getAbsolutePath() + File.separatorChar + list[i]));
59 public String getClassPath() {
60 String classpath = System.getProperty("java.class.path");
61 String [] l = new File(Root.root + "/LIB/").list();
62 for(int i=0; l != null && i<l.length; i++) {
63 if (!l[i].endsWith(".jar")) continue;
64 classpath += File.pathSeparatorChar;
65 classpath += Root.root + "/LIB/" + l[i];
67 l = new File(this.path + File.separatorChar + "LIB").list();
68 for(int i=0; l!=null && i<l.length; i++) {
69 if (!l[i].endsWith(".jar")) continue;
70 classpath += File.pathSeparatorChar;
71 classpath += this.path + "/LIB/" + l[i];
73 return classpath + File.pathSeparatorChar + this.path + "/BIN";
76 private void compileSource() throws Exception {
77 File srcdir = new File(this.path + File.separatorChar + "SRC");
78 if (!srcdir.exists()) return;
80 if (new File("/usr/bin/jikes").exists()) {
81 File bindir = new File(this.path + File.separatorChar + "BIN"); bindir.mkdirs();
82 String bootclasspath = System.getProperty("sun.boot.class.path", "");
84 args.addElement("/usr/bin/jikes");
85 args.addElement("+E");
86 args.addElement("-nowarn");
87 args.addElement("-bootclasspath");
88 args.addElement(bootclasspath);
89 args.addElement("-classpath");
90 args.addElement(getClassPath());
91 args.addElement("-sourcepath");
92 args.addElement(srcdir.getAbsolutePath());
93 args.addElement("-d");
94 args.addElement(bindir.getAbsolutePath());
96 String[] all = new String[args.size()];
98 Log.info(this, "invoking jikes");
99 for(int i=0; i<all.length; i++) Log.info(this, " " + all[i]);
100 final Process jikes = Runtime.getRuntime().exec(all);
101 final BufferedReader out = new BufferedReader(new InputStreamReader(jikes.getInputStream()));
102 final BufferedReader err = new BufferedReader(new InputStreamReader(jikes.getErrorStream()));
103 new Thread() { public void run() {
104 try { for(String s = out.readLine(); s != null; s = out.readLine()) Log.info("jikes[stdout]", s); }
105 catch (Exception e) { Log.warn("jikes", e); } } }.start();
106 new Thread() { public void run() {
107 try { for(String s = err.readLine(); s != null; s = err.readLine()) Log.info("jikes[stderr]", s); }
108 catch (Exception e) { Log.warn("jikes", e); } } }.start();
111 Log.error(this, "ACK! jikes not found, javac not (yet) supported");
115 File bindir = new File(this.path + File.separatorChar + "BIN"); bindir.mkdirs();
116 Vec args = new Vec();
117 args.addElement("/usr/bin/javac");
118 args.addElement("-nowarn");
119 args.addElement("-classpath");
120 args.addElement(getClassPath());
121 args.addElement("-sourcepath");
122 args.addElement(srcdir.getAbsolutePath());
123 args.addElement("-d");
124 args.addElement(bindir.getAbsolutePath());
126 String[] all = new String[args.size()];
128 Log.info(this, "invoking javac for " + srcdir.getAbsolutePath());
129 final Process javac = Runtime.getRuntime().exec(all, new String[] { "PATH=/bin:/usr/bin" });
130 final BufferedReader out = new BufferedReader(new InputStreamReader(javac.getInputStream()));
131 final BufferedReader err = new BufferedReader(new InputStreamReader(javac.getErrorStream()));
132 new Thread() { public void run() {
133 try { for(String s = out.readLine(); s != null; s = out.readLine()) Log.info("javac [stdout]", s); }
134 catch (Exception e) { Log.warn("javac", e); } } }.start();
135 new Thread() { public void run() {
136 try { for(String s = err.readLine(); s != null; s = err.readLine()) Log.info("javac [stderr]", s); }
137 catch (Exception e) { Log.warn("javac", e); } } }.start();
142 // only watch SRC and LIB for changes
143 public Watched slash(String path) {
144 return (path.equals("LIB") ||
145 path.equals("BIN") ||
146 path.equals("SRC") ||
147 path.endsWith(".jar") ) ? super.slash(path) : null; }
150 // dump the classloader if anything changes
151 public void changed(Watched w) {
152 if (w.path.indexOf("BIN") != -1) return;
153 if (classloader != null) {
154 Log.info(this, "killing all threads for: " + w.path);
155 Log.info(this, " thread count before kill: " + tg.activeCount());
157 try { Thread.sleep(1000); } catch (Exception e) { }
158 Log.info(this, " thread count after kill: " + tg.activeCount());
159 tg = new ThreadGroup(getAbsolutePath());
160 Log.info(this, "scheduling classes for reload due to change in: " + w.path);
165 public class TreeClassLoader extends java.net.URLClassLoader {
167 public String getClassPath() { return Loader.this.getClassPath(); }
169 public TreeClassLoader(java.net.URL[] urls) { super(urls); }
170 //private Hashtable cache = new Hashtable();
172 public InputStream getResourceAsStream(String name) { return getInputStream(name); }
174 private synchronized Class defineClass(String name) {
176 InputStream is = null;
179 is = getInputStream(name.replace('.', File.separatorChar) + ".class");
180 if (is == null) return null;
181 b = InputStreamToByteArray.convert(is);
182 } finally { if (is != null) is.close(); }
183 return defineClass(b, 0, b.length);
184 } catch (Exception e) {
190 private InputStream getInputStream(String name) {
191 // first see if it's just sitting there
192 File classFile = slash("BIN").slash(name);
193 if (classFile.exists()) try {
194 return new FileInputStream(classFile);
195 } catch (Exception e) { Log.warn(this, e); }
197 // then scan the jarfiles for it
198 File lib = slash("LIB");
199 if (lib.exists() && lib.isDirectory()) try {
200 boolean first = true;
202 String[] paths = first ? lib.list() : list();
203 for(int i=0; i<paths.length; i++) {
204 if (paths[i].endsWith(".jar")) {
205 File f = new File(getAbsolutePath()+File.separatorChar+"LIB"+File.separatorChar+paths[i]);
206 Log.debug(this, " scanning " + f.getAbsolutePath() + " for " + name);
207 ZipFile zf = new ZipFile(f);
208 ZipEntry ze = zf.getEntry(name);
209 if (ze != null) return zf.getInputStream(ze);
216 } catch (Exception e) { Log.warn(this, e); }
218 // finally, resort to compiling it if we have to
219 //File src = new File(getAbsolutePath() + File.separatorChar + "SRC");
221 //if (!sourcebuilt) buildSource();
225 public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
226 Class c = (Class)cache.get(name);
227 if (c == null) try { c = findSystemClass(name); } catch (ClassNotFoundException cfe) { }
228 if (c == null) try { c = Class.forName(name); } catch (ClassNotFoundException cfe) { }
229 if (c == null) c = defineClass(name);
230 if (c == null) throw new ClassNotFoundException();
232 if (resolve) resolveClass(c);