20d2d8404ab5659751cfa712b914aad34ee1c5cd
[org.ibex.jinetd.git] / src / org / ibex / jinetd / TreeClassLoader.java
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.
4
5 package org.ibex.jinetd;
6 import org.ibex.io.*;
7 import org.ibex.util.*;
8 import java.io.*;
9 import java.util.*;
10 import java.text.*;
11 import java.net.*;
12 import java.util.zip.*;
13
14 public class TreeClassLoader extends URLClassLoader {
15
16     private final File root;
17     private final File lib;
18     private Hashtable cache = new Hashtable();
19
20     public TreeClassLoader(File root, ClassLoader parent) {
21         super(new URL[] { }, parent);
22         System.out.println("TreeClassLoader("+root.getAbsolutePath()+")");
23         this.root = root;
24         this.lib = new File(root.getAbsolutePath() + File.separatorChar + "lib");
25     }
26
27     public Enumeration getLoadedClassNames() { return cache.keys(); }
28
29     // Classloading //////////////////////////////////////////////////////////////////////////////
30
31     public URL[] getURLs() {
32         try {
33             Vec v = new Vec();
34             if (getParent() != null && getParent() instanceof URLClassLoader) {
35                 URL[] parentUrls = ((URLClassLoader)getParent()).getURLs();
36                 for(int i=0; i<parentUrls.length; i++) v.addElement(parentUrls[i]);
37             }
38             String vmClasspath =
39                 System.getProperty("java.class.path") +
40                 File.pathSeparatorChar +
41                 System.getProperty("sun.boot.class.path");
42             StringTokenizer st = new StringTokenizer(vmClasspath, File.pathSeparatorChar+"");
43             while(st.hasMoreTokens()) v.addElement(new URL("file:" + st.nextToken()));
44             v.addElement(new URL("file:" + root.getAbsolutePath()));
45             v.addElement(new URL("file:" + root.getAbsolutePath() + File.separatorChar + "classes"));
46             for(Enumeration e = enumerateJarFiles(); e.hasMoreElements(); )
47                 v.addElement(new URL("file:" + ((File)e.nextElement()).getAbsolutePath()));
48             return (URL[])v.copyInto(new URL[v.size()]);
49         } catch (MalformedURLException e) {
50             Log.error(this, e);
51             return null;
52         }
53     }
54
55     private synchronized Class defineClass(String name) throws ClassNotFoundException {
56         InputStream is = null;
57         try {
58             is = getClassInputStream(name);
59             if (is == null) return null;
60             byte[] b = InputStreamToByteArray.convert(is);
61             Class ret = defineClass(b, 0, b.length);
62             cache.put(name, ret);
63             return ret;
64         } catch (Exception e) {
65             Log.error(this, e);
66             throw new ClassNotFoundException();
67         } finally {
68             if (is != null) try { is.close(); } catch (Exception e) { Log.error(this, e); }
69         }
70     }
71
72     public synchronized Class findClass(String name) throws ClassNotFoundException {
73         Class c = (Class)cache.get(name);
74         if (c==null) c = defineClass(name);
75         if (c==null) throw new ClassNotFoundException(name);
76         return c;
77     }
78
79     // Filesystem Methods //////////////////////////////////////////////////////////////////////////////
80
81     private static final FilenameFilter jarFilter =
82         new FilenameFilter() { public boolean accept(File f, String s) {return s.endsWith(".jar");}};
83     public Enumeration enumerateJarFiles() {
84         Enumeration rootJars =
85             new Misc.ArrayEnumeration(root.list(jarFilter)) {
86                 public Object nextElement() { return new File(root.getAbsolutePath()+File.separatorChar+super.nextElement()); } };
87         Enumeration libJars =
88             new Misc.ArrayEnumeration(lib.list(jarFilter)) {
89                 public Object nextElement() { return new File(lib.getAbsolutePath()+File.separatorChar+super.nextElement()); } };
90         return new Misc.JoinEnumeration(rootJars, libJars);
91     }
92
93     public InputStream getResourceAsStream(String name) {
94         InputStream ret = getInputStream(name);
95         if (ret == null) ret = getParent().getResourceAsStream(name);
96         return ret;
97     }
98
99     public InputStream getClassInputStream(String classname) { return getInputStream(classname.replace('.', '/')+".class"); }
100     public InputStream getInputStream(String name) {
101         try {
102             File f = new File(root.getAbsolutePath() + File.separatorChar + name);
103             if (f.exists()) return new FileInputStream(f);
104         } catch (IOException e) { /* DELIBERATE */ }
105         try {
106             File f = new File("classes" + File.separatorChar + root.getAbsolutePath() + File.separatorChar + name);
107             if (f.exists()) return new FileInputStream(f);
108         } catch (IOException e) { /* DELIBERATE */ }
109         for(Enumeration e = enumerateJarFiles(); e.hasMoreElements();) try {
110             ZipFile zf = new ZipFile((File)e.nextElement());
111             ZipEntry ze = zf.getEntry(name);
112             if (ze != null) return zf.getInputStream(ze);
113             zf.close();
114         } catch (Exception ex) { Log.warn(this, ex); }
115         return null;
116     }
117
118     // Experimental //////////////////////////////////////////////////////////////////////////////
119
120     protected ThreadGroup tg = null;
121     private void nuke() {
122         if (tg.activeCount() == 0) return;
123         Log.info(this, "killing all threads for: " + root.getAbsolutePath());
124         Log.info(this, "   thread count before interrupt: " + tg.activeCount());
125         tg.interrupt();
126         try { Thread.sleep(3000); } catch (Exception e) { Log.error(this, e); }
127         Log.info(this, "   thread count before kill: " + tg.activeCount());
128         Thread[] all = new Thread[tg.activeCount()];
129         tg.enumerate(all, true);
130         for(int i=0; i<all.length; i++) Stream.kill(all[i]);
131         try { Thread.sleep(3000); } catch (Exception e) { Log.error(this, e); }
132         Log.info(this, "   thread count after kill: " + tg.activeCount());
133         if (tg.activeCount() > 0) {
134             Log.warn(this, "    annoying threads:");
135             Thread[] annoying = new Thread[tg.activeCount()];
136             tg.enumerate(annoying, true);
137             for(int i=0; i<annoying.length; i++) {
138                 Log.warn(this, "      " + annoying[i]);
139                 StackTraceElement[] stack = annoying[i].getStackTrace();
140                 for(int j=0; j<stack.length; j++) Log.warn(this, "        " + stack[j]);
141                 Log.warn(this, " ");
142             }
143         }
144     }
145
146 }