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