import
[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.util.zip.*;
6
7 /** represents a file or directory which is scanned for updates */
8 public class Loader extends Watcher {
9
10     public Loader(String path) { super(path); }
11     
12     private TreeClassLoader classloader = new TreeClassLoader();
13     public ClassLoader getClassLoader() {
14         ClassLoader classloader = this.classloader;
15         if (classloader == null) {
16             classloader = this.classloader = new TreeClassLoader();
17             Log.warn(this, "getting classloader...");
18             try {
19                 compileSource();
20             } catch (Exception e) {
21                 Log.error(this, e);
22             }
23         }
24         return classloader;
25     }
26
27     private void fill(Vec vec, File dir) {
28         if (!dir.exists()) return;
29         if (!dir.isDirectory()) {
30             if (!dir.getPath().endsWith(".java")) return;
31             vec.addElement(dir.getAbsolutePath());
32         } else {
33             String[] list = dir.list();
34             for(int i=0; i<list.length; i++)
35                 fill(vec, new File(dir.getAbsolutePath() + File.separatorChar + list[i]));
36         }
37     }
38     private void compileSource() throws Exception {
39         File srcdir = new File(this.path + File.separatorChar + "SRC");
40         if (!srcdir.exists()) return;
41         if (new File("/usr/bin/jikes").exists()) {
42             File bindir = new File(this.path + File.separatorChar + "BIN");  bindir.mkdirs();
43             File libdir = new File(this.path + File.separatorChar + "LIB");
44             String classpath = System.getProperty("java.class.path");
45             String [] l = new File("/jinetd/LIB/").list();
46             for(int i=0; i<l.length; i++) {
47                 if (!l[i].endsWith(".jar")) continue;
48                 classpath += File.pathSeparatorChar;
49                 classpath += "/jinetd/LIB/" + l[i];
50             }
51             String bootclasspath = System.getProperty("sun.boot.class.path", "");
52             Vec args = new Vec();
53             args.addElement("/usr/bin/jikes");
54             args.addElement("+E");
55             args.addElement("-nowarn");
56             args.addElement("-bootclasspath");
57             args.addElement(bootclasspath);
58             args.addElement("-extdirs");
59             args.addElement(libdir.getAbsolutePath());
60             args.addElement("-classpath");
61             args.addElement(classpath);
62             args.addElement("-sourcepath");
63             args.addElement(srcdir.getAbsolutePath());
64             args.addElement("-d");
65             args.addElement(bindir.getAbsolutePath());
66             fill(args, srcdir);
67             String[] all = new String[args.size()];
68             args.copyInto(all);
69             Log.info(this, "invoking jikes");
70             for(int i=0; i<all.length; i++) Log.info(this, "   " + all[i]);
71             final Process jikes = Runtime.getRuntime().exec(all);
72             final BufferedReader out = new BufferedReader(new InputStreamReader(jikes.getInputStream()));
73             final BufferedReader err = new BufferedReader(new InputStreamReader(jikes.getErrorStream()));
74             new Thread() { public void run() {
75                 try { for(String s = out.readLine(); s != null; s = out.readLine()) Log.info("jikes[stdout]", s); }
76                 catch (Exception e) { Log.warn("jikes", e); } } }.start();
77             new Thread() { public void run() {
78                 try { for(String s = err.readLine(); s != null; s = err.readLine()) Log.info("jikes[stderr]", s); }
79                 catch (Exception e) { Log.warn("jikes", e); } } }.start();
80             jikes.waitFor();
81         } else {
82             Log.error(this, "ACK! jikes not found, javac not (yet) supported");
83         }
84     }
85
86     // only watch SRC and LIB for changes
87     public Watched slash(String path) {
88         return (path.equals("LIB") ||
89                 path.equals("BIN") ||
90                 path.equals("SRC") ||
91                 path.endsWith(".jar") ) ? super.slash(path) : null; }
92
93
94     // dump the classloader if anything changes
95     public void changed(Watched w) {
96         if (w.path.indexOf("BIN") != -1) return;
97         if (classloader != null) {
98             Log.info(this, "Reloading all classes: " + path);
99             classloader = null;
100         }
101     }
102     
103     private class TreeClassLoader extends ClassLoader {
104         private Hashtable cache = new Hashtable();
105
106         private synchronized Class defineClass(String name) {
107             // first see if it's just sitting there
108             File classFile = slash("BIN").slash(name.replace('.', File.separatorChar) + ".class");
109             if (classFile.exists()) {
110                 try {
111                     FileInputStream fis = new FileInputStream(classFile);
112                     byte[] b = InputStreamToByteArray.convert(fis);
113                     fis.close();
114                     Log.debug(this, "  loading " + name + " from " + classFile.getAbsolutePath());
115                     return defineClass(b, 0, b.length);
116                 } catch (Exception e) {
117                     Log.warn(this, e);
118                 }
119             }
120
121             // then scan the jarfiles for it
122             File lib = slash("LIB");
123             if (lib.exists() && lib.isDirectory()) {
124                 try {
125                     String[] paths = lib.list();
126                     for(int i=0; i<paths.length; i++) {
127                         if (paths[i].endsWith(".jar")) {
128                             File f = new File(getAbsolutePath()+File.separatorChar+"LIB"+File.separatorChar+paths[i]);
129                             //Log.debug(this, "  scanning " + f.getAbsolutePath());
130                             ZipFile zf = new ZipFile(f);
131                             ZipEntry ze = zf.getEntry(name.replace('.', File.separatorChar) + ".class");
132                             if (ze != null) {
133                                 byte[] b = InputStreamToByteArray.convert(zf.getInputStream(ze));
134                                 Log.debug(this, "    loading " + name + " from " + f.getAbsolutePath());
135                                 zf.close();
136                                 return defineClass(b, 0, b.length);
137                             }
138                             zf.close();
139                         }
140                     }
141                 } catch (Exception e) {
142                     Log.warn(this, e);
143                 }
144
145             // finally scan ourselves
146                 try {
147                     String[] paths = list();
148                     for(int i=0; i<paths.length; i++) {
149                         if (paths[i].endsWith(".jar")) {
150                             File f = new File(getAbsolutePath()+File.separatorChar+paths[i]);
151                             //Log.debug(this, "  scanning " + f.getAbsolutePath());
152                             ZipFile zf = new ZipFile(f);
153                             ZipEntry ze = zf.getEntry(name.replace('.', File.separatorChar) + ".class");
154                             if (ze != null) {
155                                 byte[] b = InputStreamToByteArray.convert(zf.getInputStream(ze));
156                                 Log.debug(this, "    loading " + name + " from " + f.getAbsolutePath());
157                                 zf.close();
158                                 return defineClass(b, 0, b.length);
159                             }
160                             zf.close();
161                         }
162                     }
163                 } catch (Exception e) {
164                     Log.warn(this, e);
165                 }
166
167             }
168                 
169             // finally, resort to compiling it if we have to
170             //File src = new File(getAbsolutePath() + File.separatorChar + "SRC");
171             // FIXME
172             //if (!sourcebuilt) buildSource();
173             return null;
174         }
175
176         public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
177             try {
178                 Class c = findSystemClass(name);
179                 if (c != null) { if (resolve) resolveClass(c); return c; }
180             } catch (ClassNotFoundException e) { /* DELIBERATE */ }
181             Class c = (Class)cache.get(name);
182             if (c == null) {
183                 //Log.info(this, "looking for class " + name);
184                 c = defineClass(name);
185                 if (c == null) throw new ClassNotFoundException();
186                 cache.put(name, c);
187             }
188             if (resolve) resolveClass(c);
189             return c;
190         }
191     }
192 }