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 }