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 Class<?> loadClass(String className, Class<?> callingClass) throws ClassNotFoundException
37 {
38 try
39 {
40 return Thread.currentThread().getContextClassLoader().loadClass(className);
41 }
42 catch (ClassNotFoundException e)
43 {
44 try
45 {
46 return Class.forName(className);
47 }
48 catch (ClassNotFoundException ex)
49 {
50 try
51 {
52 return ClassLoaderUtils.class.getClassLoader().loadClass(className);
53 }
54 catch (ClassNotFoundException exc)
55 {
56 return callingClass.getClassLoader().loadClass(className);
57 }
58
59 }
60 }
61 }
62
63 /**
64 * Load a given resource.
65 * <p>
66 * This method will try to load the resource using the following methods (in order):
67 * <ul>
68 * <li>From {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
69 * <li>From {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
70 * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
71 * </ul>
72 *
73 * @param resourceName The name of the resource to load
74 * @param callingClass The Class object of the calling object
75 */
76 public static URL getResource(String resourceName, Class<?> callingClass)
77 {
78 URL url = null;
79
80 url = Thread.currentThread().getContextClassLoader().getResource(resourceName);
81
82 if (url == null)
83 {
84 url = ClassLoaderUtils.class.getClassLoader().getResource(resourceName);
85 }
86
87 if (url == null)
88 {
89 url = callingClass.getClassLoader().getResource(resourceName);
90 }
91 return url;
92 }
93
94 /**
95 * returns all found resources as java.net.URLs.
96 * <p>
97 * This method will try to load the resource using the following methods (in order):
98 * <ul>
99 * <li>From {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()}
100 * <li>From {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()}
101 * <li>From the {@link Class#getClassLoader() callingClass.getClassLoader() }
102 * </ul>
103 *
104 * @param resourceName The name of the resource to load
105 * @param callingClass The Class object of the calling object
106 */
107 public static Enumeration<URL> getResources(String resourceName, Class<?> callingClass) throws IOException
108 {
109 Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(resourceName);
110 if (urls == null)
111 {
112 urls = ClassLoaderUtils.class.getClassLoader().getResources(resourceName);
113 if (urls == null)
114 {
115 urls = callingClass.getClassLoader().getResources(resourceName);
116 }
117 }
118
119 return urls;
120 }
121
122 /**
123 * This is a convenience method to load a resource as a stream.
124 *
125 * The algorithm used to find the resource is given in getResource()
126 *
127 * @param resourceName The name of the resource to load
128 * @param callingClass The Class object of the calling object
129 */
130 public static InputStream getResourceAsStream(String resourceName, Class<?> callingClass)
131 {
132 URL url = getResource(resourceName, callingClass);
133 try
134 {
135 return url != null ? url.openStream() : null;
136 }
137 catch (IOException e)
138 {
139 return null;
140 }
141 }
142
143 /**
144 * Prints the current classloader hierarchy - useful for debugging.
145 */
146 public static void printClassLoader()
147 {
148 System.out.println("ClassLoaderUtils.printClassLoader");
149 printClassLoader(Thread.currentThread().getContextClassLoader());
150 }
151
152 /**
153 * Prints the classloader hierarchy from a given classloader - useful for debugging.
154 */
155 public static void printClassLoader(ClassLoader cl)
156 {
157 System.out.println("ClassLoaderUtils.printClassLoader(cl = " + cl + ")");
158 if (cl != null)
159 {
160 printClassLoader(cl.getParent());
161 }
162 }
163 }