View Javadoc

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 }