1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.discovery.resource;
18
19 import java.util.Vector;
20
21 import org.apache.commons.discovery.jdk.JDKHooks;
22
23
24 /***
25 * There are many different contexts in which
26 * loaders can be used. This provides a holder
27 * for a set of class loaders, so that they
28 * don't have to be build back up everytime...
29 *
30 * @author Richard A. Sitze
31 * @author Craig R. McClanahan
32 * @author Costin Manolache
33 */
34 public class ClassLoaders
35 {
36 protected Vector classLoaders = new Vector();
37
38 /*** Construct a new class loader set
39 */
40 public ClassLoaders() {
41 }
42
43 public int size() {
44 return classLoaders.size();
45 }
46
47 public ClassLoader get(int idx) {
48 return (ClassLoader)classLoaders.elementAt(idx);
49 }
50
51 /***
52 * Specify a new class loader to be used in searching.
53 * The order of loaders determines the order of the result.
54 * It is recommended to add the most specific loaders first.
55 */
56 public void put(ClassLoader classLoader) {
57 if (classLoader != null) {
58 classLoaders.addElement(classLoader);
59 }
60 }
61
62
63 /***
64 * Specify a new class loader to be used in searching.
65 * The order of loaders determines the order of the result.
66 * It is recommended to add the most specific loaders first.
67 *
68 * @param prune if true, verify that the class loader is
69 * not an Ancestor (@see isAncestor) before
70 * adding it to our list.
71 */
72 public void put(ClassLoader classLoader, boolean prune) {
73 if (classLoader != null && !(prune && isAncestor(classLoader))) {
74 classLoaders.addElement(classLoader);
75 }
76 }
77
78
79 /***
80 * Check to see if <code>classLoader</code> is an
81 * ancestor of any contained class loader.
82 *
83 * This can be used to eliminate redundant class loaders
84 * IF all class loaders defer to parent class loaders
85 * before resolving a class.
86 *
87 * It may be that this is not always true. Therefore,
88 * this check is not done internally to eliminate
89 * redundant class loaders, but left to the discretion
90 * of the user.
91 */
92 public boolean isAncestor(final ClassLoader classLoader) {
93
94 if (classLoader == null)
95 return true;
96
97 for (int idx = 0; idx < size(); idx++) {
98 for(ClassLoader walker = get(idx);
99 walker != null;
100 walker = walker.getParent())
101 {
102 if (walker == classLoader) {
103 return true;
104 }
105 }
106 }
107 return false;
108 }
109
110
111 /***
112 * Utility method. Returns a preloaded ClassLoaders instance
113 * containing the following class loaders, in order:
114 *
115 * <ul>
116 * <li>spi.getClassLoader</li>
117 * <li>seeker.getClassLoader</li>
118 * <li>System Class Loader</li>
119 * </ul>
120 *
121 * Note that the thread context class loader is NOT present.
122 * This is a reasonable set of loaders to try if the resource to be found
123 * should be restricted to a libraries containing the SPI and Factory.
124 *
125 * @param spi WHAT is being looked for (an implementation of this class,
126 * a default property file related to this class).
127 * @param factory WHO is performing the lookup.
128 * @param prune Determines if ancestors are allowed to be loaded or not.
129 */
130 public static ClassLoaders getLibLoaders(Class spi, Class factory, boolean prune) {
131 ClassLoaders loaders = new ClassLoaders();
132
133 if (spi != null) loaders.put(spi.getClassLoader());
134 if (factory != null) loaders.put(factory.getClassLoader(), prune);
135 loaders.put(JDKHooks.getJDKHooks().getSystemClassLoader(), prune);
136
137 return loaders;
138 }
139
140 /***
141 * Utility method. Returns a preloaded ClassLoaders instance
142 * containing the following class loaders, in order:
143 *
144 * <ul>
145 * <li>Thread Context Class Loader</li>
146 * <li>spi.getClassLoader</li>
147 * <li>seeker.getClassLoader</li>
148 * <li>System Class Loader</li>
149 * </ul>
150 *
151 * Note that the thread context class loader IS present.
152 * This is a reasonable set of loaders to try if the resource to be found
153 * may be provided by an application.
154 *
155 * @param spi WHAT is being looked for (an implementation of this class,
156 * a default property file related to this class).
157 * @param factory WHO is performing the lookup (factory).
158 * @param prune Determines if ancestors are allowed to be loaded or not.
159 */
160 public static ClassLoaders getAppLoaders(Class spi, Class factory, boolean prune) {
161 ClassLoaders loaders = new ClassLoaders();
162
163 loaders.put(JDKHooks.getJDKHooks().getThreadContextClassLoader());
164 if (spi != null) loaders.put(spi.getClassLoader(), prune);
165 if (factory != null) loaders.put(factory.getClassLoader(), prune);
166 loaders.put(JDKHooks.getJDKHooks().getSystemClassLoader(), prune);
167
168 return loaders;
169 }
170 }