1 /*
2 * Atlassian Source Code Template.
3 * User: sfarquhar
4 * Date: 8/03/2002
5 * Time: 17:37:41
6 * CVS Revision: $Revision: 1.6 $
7 * Last CVS Commit: $Date: 2006/08/31 20:55:22 $
8 * Author of last CVS Commit: $Author: jnolen $
9 */
10 package com.atlassian.core.util;
11
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.net.URL;
15 import java.util.Enumeration;
16 import java.util.ResourceBundle;
17 import java.util.Locale;
18
19 ///CLOVER:OFF
20
21 /**
22 * This class is extremely useful for loading resources and classes in a fault tolerant manner
23 * that works across different applications servers.
24 * <p>
25 * It has come out of many months of frustrating use of multiple application servers at Atlassian,
26 * please don't change things unless you're sure they're not going to break in one server or another!
27 *
28 * @author $Author: jnolen $
29 * @version $Revision: 1.6 $
30 */
31 public class ClassLoaderUtils
32 {
33 /**
34 * Load a class with a given name.
35 * <p>
36 * It will try to load the class in the following order:
37 * <ul>
38 * <li>From {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
39 * <li>Using the basic {@link Class#forName(java.lang.String) }
40 * <li>From {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
41 * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
42 * </ul>
43 *
44 * @param className The name of the class to load
45 * @param callingClass The Class object of the calling object
46 * @throws ClassNotFoundException If the class cannot be found anywhere.
47 */
48 public static Class loadClass(String className, Class callingClass) throws ClassNotFoundException
49 {
50 return loadClass(className, callingClass.getClassLoader());
51 }
52
53 /**
54 * Load a class with a given name.
55 * <p>
56 * It will try to load the class in the following order:
57 * <ul>
58 * <li>From {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
59 * <li>Using the basic {@link Class#forName(java.lang.String) }
60 * <li>From {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
61 * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
62 * </ul>
63 *
64 * @param className The name of the class to load
65 * @param callingClassLoader The ClassLoader the calling object which will be used to look up className
66 * @throws ClassNotFoundException If the class cannot be found anywhere.
67 */
68 public static Class loadClass(String className, ClassLoader callingClassLoader) throws ClassNotFoundException
69 {
70 try
71 {
72 return Thread.currentThread().getContextClassLoader().loadClass(className);
73 }
74 catch (ClassNotFoundException e)
75 {
76 try
77 {
78 return Class.forName(className);
79 }
80 catch (ClassNotFoundException ex)
81 {
82 try
83 {
84 return ClassLoaderUtils.class.getClassLoader().loadClass(className);
85 }
86 catch (ClassNotFoundException exc)
87 {
88 return callingClassLoader.loadClass(className);
89 }
90
91 }
92 }
93 }
94
95
96 /**
97 * Load a given resource.
98 * <p>
99 * This method will try to load the resource using the following methods (in order):
100 * <ul>
101 * <li>From {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
102 * <li>From {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
103 * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
104 * </ul>
105 *
106 * @param resourceName The name of the resource to load
107 * @param callingClass The Class object of the calling object
108 */
109 public static URL getResource(String resourceName, Class callingClass)
110 {
111 URL url = null;
112
113 url = Thread.currentThread().getContextClassLoader().getResource(resourceName);
114
115 if (url == null)
116 {
117 url = ClassLoaderUtils.class.getClassLoader().getResource(resourceName);
118 }
119
120 if (url == null)
121 {
122 url = callingClass.getClassLoader().getResource(resourceName);
123 }
124 return url;
125 }
126
127 /**
128 * getBundle() version of getResource() (that checks against the same list of class loaders)
129 * @param resourceName
130 * @param locale
131 * @param callingClass
132 */
133 public static ResourceBundle getBundle(String resourceName, Locale locale, Class callingClass)
134 {
135 ResourceBundle bundle = null;
136
137 bundle = ResourceBundle.getBundle(resourceName, locale, Thread.currentThread().getContextClassLoader());
138
139 if (bundle == null)
140 {
141 bundle = ResourceBundle.getBundle(resourceName, locale, ClassLoaderUtils.class.getClassLoader());
142 }
143
144 if (bundle == null)
145 {
146 bundle = ResourceBundle.getBundle(resourceName, locale, callingClass.getClassLoader());
147 }
148 return bundle;
149 }
150
151 /**
152 * returns all found resources as java.net.URLs.
153 * <p>
154 * This method will try to load the resource using the following methods (in order):
155 * <ul>
156 * <li>From {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
157 * <li>From {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
158 * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
159 * </ul>
160 *
161 * @param resourceName The name of the resource to load
162 * @param callingClass The Class object of the calling object
163 */
164 public static Enumeration getResources(String resourceName, Class callingClass) throws IOException
165 {
166 Enumeration urls = Thread.currentThread().getContextClassLoader().getResources(resourceName);
167 if (urls == null)
168 {
169 urls = ClassLoaderUtils.class.getClassLoader().getResources(resourceName);
170 if (urls == null)
171 {
172 urls = callingClass.getClassLoader().getResources(resourceName);
173 }
174 }
175
176 return urls;
177 }
178
179 /**
180 * This is a convenience method to load a resource as a stream.
181 *
182 * The algorithm used to find the resource is given in getResource()
183 *
184 * @param resourceName The name of the resource to load
185 * @param callingClass The Class object of the calling object
186 */
187 public static InputStream getResourceAsStream(String resourceName, Class callingClass)
188 {
189 URL url = getResource(resourceName, callingClass);
190 try
191 {
192 return url != null ? url.openStream() : null;
193 }
194 catch (IOException e)
195 {
196 return null;
197 }
198 }
199
200 /**
201 * Prints the current classloader hierarchy - useful for debugging.
202 */
203 public static void printClassLoader()
204 {
205 System.out.println("ClassLoaderUtils.printClassLoader");
206 printClassLoader(Thread.currentThread().getContextClassLoader());
207 }
208
209 /**
210 * Prints the classloader hierarchy from a given classloader - useful for debugging.
211 */
212 public static void printClassLoader(ClassLoader cl)
213 {
214 System.out.println("ClassLoaderUtils.printClassLoader(cl = " + cl + ")");
215 if (cl != null)
216 {
217 printClassLoader(cl.getParent());
218 }
219 }
220 }