8f9fef83372abbee6b68f06874d56296e7510745
[org.ibex.jinetd.git] / src / org / ibex / jinetd / Loader.java
1 package org.ibex.jinetd;
2 import org.ibex.util.*;
3 import java.io.*;
4 import java.util.*;
5 import java.text.*;
6 import java.net.*;
7 import java.util.zip.*;
8
9 /** represents a file or directory which is scanned for updates */
10 public class Loader extends Watcher {
11
12     ClassLoader parentClassLoader = null;
13     static final ClassLoader mycl = Loader.class.getClassLoader();
14
15     protected ThreadGroup tg = new ThreadGroup(getAbsolutePath());
16
17     public Loader(String path) { super(path); }
18     //public Loader(String path, ClassLoader pcl) { super(path); this.parentClassLoader = pcl; }
19     
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()];
28             try {
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);
35                 }
36             } catch (MalformedURLException e) {
37                 Log.error(this, e);
38                 return null;
39             }
40             classloader = this.classloader = new TreeClassLoader(urls/*, parentClassLoader*/);
41             try { compileSource(); } catch (Exception e) { Log.error(this, e); }
42         }
43         return classloader;
44     }
45
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());
51         } else {
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]));
55         }
56     }
57
58
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];
66         }
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];
72         }
73         return classpath + File.pathSeparatorChar + this.path + "/BIN";
74     }
75
76     private void compileSource() throws Exception {
77         File srcdir = new File(this.path + File.separatorChar + "SRC");
78         if (!srcdir.exists()) return;
79         /*
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", "");
83             Vec args = new Vec();
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());
95             fill(args, srcdir);
96             String[] all = new String[args.size()];
97             args.copyInto(all);
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();
109             jikes.waitFor();
110         } else {
111             Log.error(this, "ACK! jikes not found, javac not (yet) supported");
112         }
113         */
114
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());
125             fill(args, srcdir);
126             String[] all = new String[args.size()];
127             args.copyInto(all);
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();
138             javac.waitFor();
139
140     }
141
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; }
148
149
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());
156             tg.interrupt();
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);
161             classloader = null;
162         }
163     }
164     
165     public class TreeClassLoader extends java.net.URLClassLoader {
166
167         public String getClassPath() { return Loader.this.getClassPath(); }
168
169         public TreeClassLoader(java.net.URL[] urls) { super(urls); }
170         //private Hashtable cache = new Hashtable();
171         /*
172         public InputStream getResourceAsStream(String name) { return getInputStream(name); }
173
174         private synchronized Class defineClass(String name) {
175             try {
176                 InputStream is = null;
177                 byte[] b = null;
178                 try {
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) {
185                 Log.error(this, e);
186                 return null;
187             }
188         }
189
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); }
196
197             // then scan the jarfiles for it
198             File lib = slash("LIB");
199             if (lib.exists() && lib.isDirectory()) try {
200                 boolean first = true;
201                 while(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);
210                             zf.close();
211                         }
212                     }
213                     if (!first) break;
214                     first = false;
215                 }
216             } catch (Exception e) { Log.warn(this, e); }
217
218             // finally, resort to compiling it if we have to
219             //File src = new File(getAbsolutePath() + File.separatorChar + "SRC");
220             // FIXME
221             //if (!sourcebuilt) buildSource();
222             return null;
223         }
224
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();
231             cache.put(name, c);
232             if (resolve) resolveClass(c);
233             return c;
234         }
235         */
236     }
237 }