1 package com.atlassian.plugin.util;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.net.URL;
6 import java.util.Enumeration;
7
8 ///CLOVER:OFF
9 /**
10 * This class is extremely useful for loading resources and classes in a fault tolerant manner
11 * that works across different applications servers.
12 * <p>
13 * It has come out of many months of frustrating use of multiple application servers at Atlassian,
14 * please don't change things unless you're sure they're not going to break in one server or another!
15 *
16 * @author $Author: mcannon $
17 * @version $Revision: 1.1 $
18 */
19 public class ClassLoaderUtils
20 {
21 /**
22 * Load a class with a given name.
23 * <p>
24 * It will try to load the class in the following order:
25 * <ul>
26 * <li>From {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
27 * <li>Using the basic {@link Class#forName(java.lang.String) }
28 * <li>From {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
29 * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
30 * </ul>
31 *
32 * @param className The name of the class to load
33 * @param callingClass The Class object of the calling object
34 * @throws ClassNotFoundException If the class cannot be found anywhere.
35 */
36 public static <T> Class<T> loadClass(final String className, final Class<?> callingClass) throws ClassNotFoundException
37 {
38 try
39 {
40 return coerce(Thread.currentThread().getContextClassLoader().loadClass(className));
41 }
42 catch (final ClassNotFoundException e)
43 {
44 try
45 {
46 return coerce(Class.forName(className));
47 }
48 catch (final ClassNotFoundException ex)
49 {
50 try
51 {
52 return coerce(ClassLoaderUtils.class.getClassLoader().loadClass(className));
53 }
54 catch (final ClassNotFoundException exc)
55 {
56 if ((callingClass != null) && (callingClass.getClassLoader() != null))
57 {
58 return coerce(callingClass.getClassLoader().loadClass(className));
59 }
60 else
61 {
62 throw exc;
63 }
64 }
65 }
66 }
67 }
68
69 private static <T> Class<T> coerce(final Class<?> klass)
70 {
71 @SuppressWarnings("unchecked")
72 final Class<T> result = (Class<T>) klass;
73 return result;
74 }
75
76 /**
77 * Load a given resource.
78 * <p>
79 * This method will try to load the resource using the following methods (in order):
80 * <ul>
81 * <li>From {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
82 * <li>From {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
83 * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
84 * </ul>
85 *
86 * @param resourceName The name of the resource to load
87 * @param callingClass The Class object of the calling object
88 */
89 public static URL getResource(final String resourceName, final Class<?> callingClass)
90 {
91 URL url = null;
92
93 url = Thread.currentThread().getContextClassLoader().getResource(resourceName);
94
95 if (url == null)
96 {
97 url = ClassLoaderUtils.class.getClassLoader().getResource(resourceName);
98 }
99
100 if (url == null)
101 {
102 url = callingClass.getClassLoader().getResource(resourceName);
103 }
104 return url;
105 }
106
107 /**
108 * returns all found resources as java.net.URLs.
109 * <p>
110 * This method will try to load the resource using the following methods (in order):
111 * <ul>
112 * <li>From {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
113 * <li>From {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
114 * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
115 * </ul>
116 *
117 * @param resourceName The name of the resource to load
118 * @param callingClass The Class object of the calling object
119 */
120 public static Enumeration<URL> getResources(final String resourceName, final Class<?> callingClass) throws IOException
121 {
122 Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(resourceName);
123 if (urls == null)
124 {
125 urls = ClassLoaderUtils.class.getClassLoader().getResources(resourceName);
126 if (urls == null)
127 {
128 urls = callingClass.getClassLoader().getResources(resourceName);
129 }
130 }
131
132 return urls;
133 }
134
135 /**
136 * This is a convenience method to load a resource as a stream.
137 *
138 * The algorithm used to find the resource is given in getResource()
139 *
140 * @param resourceName The name of the resource to load
141 * @param callingClass The Class object of the calling object
142 */
143 public static InputStream getResourceAsStream(final String resourceName, final Class<?> callingClass)
144 {
145 final URL url = getResource(resourceName, callingClass);
146 try
147 {
148 return url != null ? url.openStream() : null;
149 }
150 catch (final IOException e)
151 {
152 return null;
153 }
154 }
155
156 /**
157 * Prints the current classloader hierarchy - useful for debugging.
158 */
159 public static void printClassLoader()
160 {
161 System.out.println("ClassLoaderUtils.printClassLoader");
162 printClassLoader(Thread.currentThread().getContextClassLoader());
163 }
164
165 /**
166 * Prints the classloader hierarchy from a given classloader - useful for debugging.
167 */
168 public static void printClassLoader(final ClassLoader cl)
169 {
170 System.out.println("ClassLoaderUtils.printClassLoader(cl = " + cl + ")");
171 if (cl != null)
172 {
173 printClassLoader(cl.getParent());
174 }
175 }
176 }