1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.codehaus.groovy.tools;
47
48 import java.net.URL;
49 import java.net.URLClassLoader;
50
51 /***
52 * This ClassLoader should be used as root of class loaders. Any
53 * RootLoader does have it's own classpath. When searching for a
54 * class or resource this classpath will be used. Parent
55 * Classloaders are ignored first. If a class or resource
56 * can't be found in the classpath of the RootLoader, then parent is
57 * checked.
58 *
59 * <b>Note:</b> this is very against the normal behavior of
60 * classloaders. Normal is to frist check parent and then look in
61 * the ressources you gave this classloader.
62 *
63 * It's possible to add urls to the classpath at runtime through
64 * @see #addURL(URL)
65 *
66 * <b>Why using RootLoader?</b>
67 * If you have to load classes with multiple classloaders and a
68 * classloader does know a class which depends on a class only
69 * a child of this loader does know, then you won't be able to
70 * load the class. To load the class the child is not allowed
71 * to redirect it's search for the class to the parent first.
72 * That way the child can load the class. If the child does not
73 * have all classes to do this, this fails of course.
74 *
75 * For example:
76 *
77 * <pre>
78 * parentLoader (has classpath: a.jar;c.jar)
79 * |
80 * |
81 * childLoader (has classpath: a.jar;b.jar;c.jar)
82 * </pre>
83 *
84 * class C (from c.jar) extends B (from b.jar)
85 *
86 * childLoader.find("C")
87 * --> parentLoader does know C.class, try to load it
88 * --> to load C.class it has to load B.class
89 * --> parentLoader is unable to find B.class in a.jar or c.jar
90 * --> NoClassDefFoundException!
91 *
92 * if childLoader had tried to load the class by itself, there
93 * would be no problem. Changing childLoader to be a RootLoader
94 * instance will solve that problem.
95 *
96 * @author Jochen Theodorou
97 */
98 public class RootLoader extends URLClassLoader {
99
100 /***
101 * constructs a new RootLoader without classpath
102 * @param parent the parent Loader
103 */
104 private RootLoader(ClassLoader parent) {
105 this(new URL[0],parent);
106 }
107
108 /***
109 * constructs a new RootLoader with a parent loader and an
110 * array of URLs as classpath
111 */
112 public RootLoader(URL[] urls, ClassLoader parent) {
113 super(urls,parent);
114 }
115
116 private static ClassLoader chooseParent(){
117 ClassLoader cl = RootLoader.class.getClassLoader();
118 if (cl!=null) return cl;
119 return ClassLoader.getSystemClassLoader();
120 }
121
122 /***
123 * constructs a new RootLoader with a @see LoaderConfiguration
124 * object which holds the classpath
125 */
126 public RootLoader(LoaderConfiguration lc) {
127 this(chooseParent());
128 Thread.currentThread().setContextClassLoader(this);
129 URL[] urls = lc.getClassPathUrls();
130 for (int i=0; i<urls.length; i++) {
131 addURL(urls[i]);
132 }
133 }
134
135 /***
136 * loads a class using the name of the class
137 */
138 protected Class loadClass(final String name, boolean resolve) throws ClassNotFoundException {
139 Class c = this.findLoadedClass(name);
140 if (c!=null) return c;
141
142 try {
143 c = findClass(name);
144 } catch (ClassNotFoundException cnfe) {}
145 if (c==null) c= super.loadClass(name,resolve);
146
147 if (resolve) resolveClass(c);
148
149 return c;
150 }
151
152 /***
153 * returns the URL of a resource, or null if it is not found
154 */
155 public URL getResource(String name) {
156 URL url = findResource(name);
157 if (url==null) url=super.getResource(name);
158 return url;
159 }
160
161 /***
162 * adds an url to the classpath of this classloader
163 */
164 public void addURL(URL url) {
165 super.addURL(url);
166 }
167 }