b166df654bc76bbb1c3f50276fc87a314cc929f3
[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     public Loader(String path) { super(path); }
15     //public Loader(String path, ClassLoader pcl) { super(path); this.parentClassLoader = pcl; }
16     
17     private TreeClassLoader classloader = null;
18     public synchronized ClassLoader getClassLoader() {
19         ClassLoader classloader = this.classloader;
20         if (classloader == null) {
21             String s = getClassPath();
22             StringTokenizer st = new StringTokenizer(s, File.pathSeparatorChar+"");
23             URL[] urls = new URL[st.countTokens()];
24             try {
25                 for(int i=0; i<urls.length; i++) {
26                     String us = st.nextToken();
27                     //if (us.endsWith(".jar")) us = "jar:file:"+us+"!/";
28                     if (us.endsWith(".jar")) us = "file:"+us;
29                     else us = "file:"+us+"/";
30                     urls[i] = new URL(us);
31                     Log.warn("[classpath]", urls[i].toString());
32                 }
33             } catch (MalformedURLException e) {
34                 Log.error(this, e);
35                 return null;
36             }
37             classloader = this.classloader = new TreeClassLoader(urls/*, parentClassLoader*/);
38             try { compileSource(); } catch (Exception e) { Log.error(this, e); }
39         }
40         return classloader;
41     }
42
43     private void fill(Vec vec, File dir) {
44         if (!dir.exists()) return;
45         if (!dir.isDirectory()) {
46             if (!dir.getPath().endsWith(".java")) return;
47             vec.addElement(dir.getAbsolutePath());
48         } else {
49             String[] list = dir.list();
50             for(int i=0; i<list.length; i++)
51                 fill(vec, new File(dir.getAbsolutePath() + File.separatorChar + list[i]));
52         }
53     }
54
55     public String getClassPath() {
56         String classpath = System.getProperty("java.class.path");
57         String [] l = new File(Root.root + "/LIB/").list();
58         for(int i=0; i<l.length; i++) {
59             if (!l[i].endsWith(".jar")) continue;
60             classpath += File.pathSeparatorChar;
61             classpath += Root.root + "/LIB/" + l[i];
62         }
63         l = new File(this.path + File.separatorChar + "LIB").list();
64         for(int i=0; l!=null && i<l.length; i++) {
65             if (!l[i].endsWith(".jar")) continue;
66             classpath += File.pathSeparatorChar;
67             classpath += this.path + "/LIB/" + l[i];
68         }
69         return classpath + File.pathSeparatorChar + this.path + "/BIN";
70     }
71
72     private void compileSource() throws Exception {
73         File srcdir = new File(this.path + File.separatorChar + "SRC");
74         if (!srcdir.exists()) return;
75         /*
76         if (new File("/usr/bin/jikes").exists()) {
77             File bindir = new File(this.path + File.separatorChar + "BIN");  bindir.mkdirs();
78             String bootclasspath = System.getProperty("sun.boot.class.path", "");
79             Vec args = new Vec();
80             args.addElement("/usr/bin/jikes");
81             args.addElement("+E");
82             args.addElement("-nowarn");
83             args.addElement("-bootclasspath");
84             args.addElement(bootclasspath);
85             args.addElement("-classpath");
86             args.addElement(getClassPath());
87             args.addElement("-sourcepath");
88             args.addElement(srcdir.getAbsolutePath());
89             args.addElement("-d");
90             args.addElement(bindir.getAbsolutePath());
91             fill(args, srcdir);
92             String[] all = new String[args.size()];
93             args.copyInto(all);
94             Log.info(this, "invoking jikes");
95             for(int i=0; i<all.length; i++) Log.info(this, "   " + all[i]);
96             final Process jikes = Runtime.getRuntime().exec(all);
97             final BufferedReader out = new BufferedReader(new InputStreamReader(jikes.getInputStream()));
98             final BufferedReader err = new BufferedReader(new InputStreamReader(jikes.getErrorStream()));
99             new Thread() { public void run() {
100                 try { for(String s = out.readLine(); s != null; s = out.readLine()) Log.info("jikes[stdout]", s); }
101                 catch (Exception e) { Log.warn("jikes", e); } } }.start();
102             new Thread() { public void run() {
103                 try { for(String s = err.readLine(); s != null; s = err.readLine()) Log.info("jikes[stderr]", s); }
104                 catch (Exception e) { Log.warn("jikes", e); } } }.start();
105             jikes.waitFor();
106         } else {
107             Log.error(this, "ACK! jikes not found, javac not (yet) supported");
108         }
109         */
110
111             File bindir = new File(this.path + File.separatorChar + "BIN");  bindir.mkdirs();
112             Vec args = new Vec();
113             args.addElement("/usr/bin/javac");
114             args.addElement("-nowarn");
115             args.addElement("-classpath");
116             args.addElement(getClassPath());
117             args.addElement("-sourcepath");
118             args.addElement(srcdir.getAbsolutePath());
119             args.addElement("-d");
120             args.addElement(bindir.getAbsolutePath());
121             fill(args, srcdir);
122             String[] all = new String[args.size()];
123             args.copyInto(all);
124             Log.info(this, "invoking javac for " + srcdir.getAbsolutePath());
125             final Process javac = Runtime.getRuntime().exec(all);
126             final BufferedReader out = new BufferedReader(new InputStreamReader(javac.getInputStream()));
127             final BufferedReader err = new BufferedReader(new InputStreamReader(javac.getErrorStream()));
128             new Thread() { public void run() {
129                 try { for(String s = out.readLine(); s != null; s = out.readLine()) Log.info("javac [stdout]", s); }
130                 catch (Exception e) { Log.warn("javac", e); } } }.start();
131             new Thread() { public void run() {
132                 try { for(String s = err.readLine(); s != null; s = err.readLine()) Log.info("javac [stderr]", s); }
133                 catch (Exception e) { Log.warn("javac", e); } } }.start();
134             javac.waitFor();
135
136     }
137
138     // only watch SRC and LIB for changes
139     public Watched slash(String path) {
140         return (path.equals("LIB") ||
141                 path.equals("BIN") ||
142                 path.equals("SRC") ||
143                 path.endsWith(".jar") ) ? super.slash(path) : null; }
144
145
146     // dump the classloader if anything changes
147     public void changed(Watched w) {
148         if (w.path.indexOf("BIN") != -1) return;
149         if (classloader != null) {
150             Log.info(this, "scheduling classes for reload due to change in: " + w.path);
151             classloader = null;
152         }
153     }
154     
155     public class TreeClassLoader extends java.net.URLClassLoader {
156
157         public String getClassPath() { return Loader.this.getClassPath(); }
158
159         public TreeClassLoader(java.net.URL[] urls) { super(urls); }
160         //private Hashtable cache = new Hashtable();
161         /*
162         public InputStream getResourceAsStream(String name) { return getInputStream(name); }
163
164         private synchronized Class defineClass(String name) {
165             try {
166                 InputStream is = null;
167                 byte[] b = null;
168                 try {
169                     is = getInputStream(name.replace('.', File.separatorChar) + ".class");
170                     if (is == null) return null;
171                     b = InputStreamToByteArray.convert(is);
172                 } finally { if (is != null) is.close(); }
173                 return defineClass(b, 0, b.length);
174             } catch (Exception e) {
175                 Log.error(this, e);
176                 return null;
177             }
178         }
179
180         private InputStream getInputStream(String name) {
181             // first see if it's just sitting there
182             File classFile = slash("BIN").slash(name);
183             if (classFile.exists()) try {
184                 return new FileInputStream(classFile);
185             } catch (Exception e) { Log.warn(this, e); }
186
187             // then scan the jarfiles for it
188             File lib = slash("LIB");
189             if (lib.exists() && lib.isDirectory()) try {
190                 boolean first = true;
191                 while(true) {
192                     String[] paths = first ? lib.list() : list(); 
193                     for(int i=0; i<paths.length; i++) {
194                         if (paths[i].endsWith(".jar")) {
195                             File f = new File(getAbsolutePath()+File.separatorChar+"LIB"+File.separatorChar+paths[i]);
196                             Log.debug(this, "  scanning " + f.getAbsolutePath() + " for " + name);
197                             ZipFile zf = new ZipFile(f);
198                             ZipEntry ze = zf.getEntry(name);
199                             if (ze != null) return zf.getInputStream(ze);
200                             zf.close();
201                         }
202                     }
203                     if (!first) break;
204                     first = false;
205                 }
206             } catch (Exception e) { Log.warn(this, e); }
207
208             // finally, resort to compiling it if we have to
209             //File src = new File(getAbsolutePath() + File.separatorChar + "SRC");
210             // FIXME
211             //if (!sourcebuilt) buildSource();
212             return null;
213         }
214
215         public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
216             Class c = (Class)cache.get(name);
217             if (c == null) try { c = findSystemClass(name); } catch (ClassNotFoundException cfe) { }
218             if (c == null) try { c = Class.forName(name); } catch (ClassNotFoundException cfe) { }
219             if (c == null) c = defineClass(name);
220             if (c == null) throw new ClassNotFoundException();
221             cache.put(name, c);
222             if (resolve) resolveClass(c);
223             return c;
224         }
225         */
226     }
227 }