1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
5 package org.ibex.jinetd;
7 import org.ibex.util.*;
12 import java.util.zip.*;
14 /** represents a file or directory which is scanned for updates */
15 public class Loader extends Watcher {
17 ClassLoader parentClassLoader = null;
18 static final ClassLoader mycl = Loader.class.getClassLoader();
20 protected ThreadGroup tg = new ThreadGroup(getAbsolutePath());
22 public Loader(String path) { super(path); }
23 //public Loader(String path, ClassLoader pcl) { super(path); this.parentClassLoader = pcl; }
25 private TreeClassLoader classloader = null;
26 public synchronized void scan() throws IOException { super.scan(); }
27 public synchronized ClassLoader getClassLoader() {
28 ClassLoader classloader = this.classloader;
29 if (classloader == null) {
30 String s = getClassPath();
31 StringTokenizer st = new StringTokenizer(s, File.pathSeparatorChar+"");
32 URL[] urls = new URL[st.countTokens()];
34 for(int i=0; i<urls.length; i++) {
35 String us = st.nextToken();
36 //if (us.endsWith(".jar")) us = "jar:file:"+us+"!/";
37 if (us.endsWith(".jar")) us = "file:"+us;
38 else us = "file:"+us+"/";
39 urls[i] = new URL(us);
41 } catch (MalformedURLException e) {
45 classloader = this.classloader = new TreeClassLoader(urls/*, parentClassLoader*/);
46 try { compileSource(); } catch (Exception e) { Log.error(this, e); }
51 private void fill(Vec vec, File dir) {
52 if (!dir.exists()) return;
53 if (!dir.isDirectory()) {
54 if (!dir.getPath().endsWith(".java")) return;
55 vec.addElement(dir.getAbsolutePath());
57 String[] list = dir.list();
58 for(int i=0; i<list.length; i++)
59 fill(vec, new File(dir.getAbsolutePath() + File.separatorChar + list[i]));
64 public String getClassPath() {
65 String classpath = System.getProperty("java.class.path");
66 String [] l = new File(Root.root + "/LIB/").list();
67 for(int i=0; l != null && i<l.length; i++) {
68 if (!l[i].endsWith(".jar")) continue;
69 classpath += File.pathSeparatorChar;
70 classpath += Root.root + "/LIB/" + l[i];
72 l = new File(this.path + File.separatorChar + "LIB").list();
73 for(int i=0; l!=null && i<l.length; i++) {
74 if (!l[i].endsWith(".jar")) continue;
75 classpath += File.pathSeparatorChar;
76 classpath += this.path + "/LIB/" + l[i];
78 return classpath + File.pathSeparatorChar + this.path + "/BIN";
81 private void compileSource() throws Exception {
82 File srcdir = new File(this.path + File.separatorChar + "SRC");
83 if (!srcdir.exists()) return;
85 if (new File("/usr/bin/jikes").exists()) {
86 File bindir = new File(this.path + File.separatorChar + "BIN"); bindir.mkdirs();
87 String bootclasspath = System.getProperty("sun.boot.class.path", "");
89 args.addElement("/usr/bin/jikes");
90 args.addElement("+E");
91 args.addElement("-nowarn");
92 args.addElement("-bootclasspath");
93 args.addElement(bootclasspath);
94 args.addElement("-classpath");
95 args.addElement(getClassPath());
96 args.addElement("-sourcepath");
97 args.addElement(srcdir.getAbsolutePath());
98 args.addElement("-d");
99 args.addElement(bindir.getAbsolutePath());
101 String[] all = new String[args.size()];
103 Log.info(this, "invoking jikes");
104 for(int i=0; i<all.length; i++) Log.info(this, " " + all[i]);
105 final Process jikes = Runtime.getRuntime().exec(all);
106 final BufferedReader out = new BufferedReader(new InputStreamReader(jikes.getInputStream()));
107 final BufferedReader err = new BufferedReader(new InputStreamReader(jikes.getErrorStream()));
108 new Thread() { public void run() {
109 try { for(String s = out.readLine(); s != null; s = out.readLine()) Log.info("jikes[stdout]", s); }
110 catch (Exception e) { Log.warn("jikes", e); } } }.start();
111 new Thread() { public void run() {
112 try { for(String s = err.readLine(); s != null; s = err.readLine()) Log.info("jikes[stderr]", s); }
113 catch (Exception e) { Log.warn("jikes", e); } } }.start();
116 Log.error(this, "ACK! jikes not found, javac not (yet) supported");
120 File bindir = new File(this.path + File.separatorChar + "BIN"); bindir.mkdirs();
121 Vec args = new Vec();
122 args.addElement("/usr/bin/javac");
123 args.addElement("-nowarn");
124 args.addElement("-classpath");
125 args.addElement(getClassPath());
126 args.addElement("-sourcepath");
127 args.addElement(srcdir.getAbsolutePath());
128 args.addElement("-d");
129 args.addElement(bindir.getAbsolutePath());
131 String[] all = new String[args.size()];
133 Log.info(this, "invoking javac for " + srcdir.getAbsolutePath());
134 final Process javac = Runtime.getRuntime().exec(all, new String[] { "PATH=/bin:/usr/bin" });
135 final BufferedReader out = new BufferedReader(new InputStreamReader(javac.getInputStream()));
136 final BufferedReader err = new BufferedReader(new InputStreamReader(javac.getErrorStream()));
137 new Thread() { public void run() {
138 try { for(String s = out.readLine(); s != null; s = out.readLine()) Log.info("javac [stdout]", s); }
139 catch (Exception e) { Log.warn("javac", e); } } }.start();
140 new Thread() { public void run() {
141 try { for(String s = err.readLine(); s != null; s = err.readLine()) Log.info("javac [stderr]", s); }
142 catch (Exception e) { Log.warn("javac", e); } } }.start();
147 // only watch SRC and LIB for changes
148 public Watched slash(String path) {
149 return (path.equals("LIB") ||
150 path.equals("BIN") ||
151 path.equals("SRC") ||
152 path.endsWith(".jar") ) ? super.slash(path) : null; }
155 private void nuke() {
156 if (tg.activeCount() == 0) return;
157 Log.info(this, "killing all threads for: " + path);
158 Log.info(this, " thread count before interrupt: " + tg.activeCount());
160 try { Thread.sleep(3000); } catch (Exception e) { Log.error(this, e); }
161 Log.info(this, " thread count before kill: " + tg.activeCount());
162 Thread[] all = new Thread[tg.activeCount()];
163 tg.enumerate(all, true);
164 for(int i=0; i<all.length; i++) Stream.kill(all[i]);
165 try { Thread.sleep(3000); } catch (Exception e) { Log.error(this, e); }
166 Log.info(this, " thread count after kill: " + tg.activeCount());
167 if (tg.activeCount() > 0) {
168 Log.warn(this, " annoying threads:");
169 Thread[] annoying = new Thread[tg.activeCount()];
170 tg.enumerate(annoying, true);
171 for(int i=0; i<annoying.length; i++) {
172 Log.warn(this, " " + annoying[i]);
173 StackTraceElement[] stack = annoying[i].getStackTrace();
174 for(int j=0; j<stack.length; j++) Log.warn(this, " " + stack[j]);
180 // dump the classloader if anything changes
181 public void changed(Watched w) {
182 if (w.path.indexOf("BIN") != -1) return;
183 if (classloader != null) {
184 for(int i=0; i<3; i++) nuke();
185 tg = new ThreadGroup(getAbsolutePath());
186 Log.info(this, "scheduling classes for reload due to change in: " + w.path);
191 public class TreeClassLoader extends java.net.URLClassLoader {
193 public String getClassPath() { return Loader.this.getClassPath(); }
195 public TreeClassLoader(java.net.URL[] urls) { super(urls); }
196 //private Hashtable cache = new Hashtable();
198 public InputStream getResourceAsStream(String name) { return getInputStream(name); }
200 private synchronized Class defineClass(String name) {
202 InputStream is = null;
205 is = getInputStream(name.replace('.', File.separatorChar) + ".class");
206 if (is == null) return null;
207 b = InputStreamToByteArray.convert(is);
208 } finally { if (is != null) is.close(); }
209 return defineClass(b, 0, b.length);
210 } catch (Exception e) {
216 private InputStream getInputStream(String name) {
217 // first see if it's just sitting there
218 File classFile = slash("BIN").slash(name);
219 if (classFile.exists()) try {
220 return new FileInputStream(classFile);
221 } catch (Exception e) { Log.warn(this, e); }
223 // then scan the jarfiles for it
224 File lib = slash("LIB");
225 if (lib.exists() && lib.isDirectory()) try {
226 boolean first = true;
228 String[] paths = first ? lib.list() : list();
229 for(int i=0; i<paths.length; i++) {
230 if (paths[i].endsWith(".jar")) {
231 File f = new File(getAbsolutePath()+File.separatorChar+"LIB"+File.separatorChar+paths[i]);
232 Log.debug(this, " scanning " + f.getAbsolutePath() + " for " + name);
233 ZipFile zf = new ZipFile(f);
234 ZipEntry ze = zf.getEntry(name);
235 if (ze != null) return zf.getInputStream(ze);
242 } catch (Exception e) { Log.warn(this, e); }
244 // finally, resort to compiling it if we have to
245 //File src = new File(getAbsolutePath() + File.separatorChar + "SRC");
247 //if (!sourcebuilt) buildSource();
251 public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
252 Class c = (Class)cache.get(name);
253 if (c == null) try { c = findSystemClass(name); } catch (ClassNotFoundException cfe) { }
254 if (c == null) try { c = Class.forName(name); } catch (ClassNotFoundException cfe) { }
255 if (c == null) c = defineClass(name);
256 if (c == null) throw new ClassNotFoundException();
258 if (resolve) resolveClass(c);