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