View Javadoc
1   /*
2    *    Copyright 2009-2023 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       https://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.apache.ibatis.io;
17  
18  import java.io.InputStream;
19  import java.net.URL;
20  
21  /**
22   * A class to wrap access to multiple class loaders making them work as one
23   *
24   * @author Clinton Begin
25   */
26  public class ClassLoaderWrapper {
27  
28    ClassLoader defaultClassLoader;
29    ClassLoader systemClassLoader;
30  
31    ClassLoaderWrapper() {
32      try {
33        systemClassLoader = ClassLoader.getSystemClassLoader();
34      } catch (SecurityException ignored) {
35        // AccessControlException on Google App Engine
36      }
37    }
38  
39    /**
40     * Get a resource as a URL using the current class path
41     *
42     * @param resource
43     *          - the resource to locate
44     *
45     * @return the resource or null
46     */
47    public URL getResourceAsURL(String resource) {
48      return getResourceAsURL(resource, getClassLoaders(null));
49    }
50  
51    /**
52     * Get a resource from the classpath, starting with a specific class loader
53     *
54     * @param resource
55     *          - the resource to find
56     * @param classLoader
57     *          - the first classloader to try
58     *
59     * @return the stream or null
60     */
61    public URL getResourceAsURL(String resource, ClassLoader classLoader) {
62      return getResourceAsURL(resource, getClassLoaders(classLoader));
63    }
64  
65    /**
66     * Get a resource from the classpath
67     *
68     * @param resource
69     *          - the resource to find
70     *
71     * @return the stream or null
72     */
73    public InputStream getResourceAsStream(String resource) {
74      return getResourceAsStream(resource, getClassLoaders(null));
75    }
76  
77    /**
78     * Get a resource from the classpath, starting with a specific class loader
79     *
80     * @param resource
81     *          - the resource to find
82     * @param classLoader
83     *          - the first class loader to try
84     *
85     * @return the stream or null
86     */
87    public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
88      return getResourceAsStream(resource, getClassLoaders(classLoader));
89    }
90  
91    /**
92     * Find a class on the classpath (or die trying)
93     *
94     * @param name
95     *          - the class to look for
96     *
97     * @return - the class
98     *
99     * @throws ClassNotFoundException
100    *           Duh.
101    */
102   public Class<?> classForName(String name) throws ClassNotFoundException {
103     return classForName(name, getClassLoaders(null));
104   }
105 
106   /**
107    * Find a class on the classpath, starting with a specific classloader (or die trying)
108    *
109    * @param name
110    *          - the class to look for
111    * @param classLoader
112    *          - the first classloader to try
113    *
114    * @return - the class
115    *
116    * @throws ClassNotFoundException
117    *           Duh.
118    */
119   public Class<?> classForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
120     return classForName(name, getClassLoaders(classLoader));
121   }
122 
123   /**
124    * Try to get a resource from a group of classloaders
125    *
126    * @param resource
127    *          - the resource to get
128    * @param classLoader
129    *          - the classloaders to examine
130    *
131    * @return the resource or null
132    */
133   InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
134     for (ClassLoader cl : classLoader) {
135       if (null != cl) {
136 
137         // try to find the resource as passed
138         InputStream returnValue = cl.getResourceAsStream(resource);
139 
140         // now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
141         if (null == returnValue) {
142           returnValue = cl.getResourceAsStream("/" + resource);
143         }
144 
145         if (null != returnValue) {
146           return returnValue;
147         }
148       }
149     }
150     return null;
151   }
152 
153   /**
154    * Get a resource as a URL using the current class path
155    *
156    * @param resource
157    *          - the resource to locate
158    * @param classLoader
159    *          - the class loaders to examine
160    *
161    * @return the resource or null
162    */
163   URL getResourceAsURL(String resource, ClassLoader[] classLoader) {
164 
165     URL url;
166 
167     for (ClassLoader cl : classLoader) {
168 
169       if (null != cl) {
170 
171         // look for the resource as passed in...
172         url = cl.getResource(resource);
173 
174         // ...but some class loaders want this leading "/", so we'll add it
175         // and try again if we didn't find the resource
176         if (null == url) {
177           url = cl.getResource("/" + resource);
178         }
179 
180         // "It's always in the last place I look for it!"
181         // ... because only an idiot would keep looking for it after finding it, so stop looking already.
182         if (null != url) {
183           return url;
184         }
185 
186       }
187 
188     }
189 
190     // didn't find it anywhere.
191     return null;
192 
193   }
194 
195   /**
196    * Attempt to load a class from a group of classloaders
197    *
198    * @param name
199    *          - the class to load
200    * @param classLoader
201    *          - the group of classloaders to examine
202    *
203    * @return the class
204    *
205    * @throws ClassNotFoundException
206    *           - Remember the wisdom of Judge Smails: Well, the world needs ditch diggers, too.
207    */
208   Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {
209 
210     for (ClassLoader cl : classLoader) {
211 
212       if (null != cl) {
213 
214         try {
215 
216           return Class.forName(name, true, cl);
217 
218         } catch (ClassNotFoundException e) {
219           // we'll ignore this until all classloaders fail to locate the class
220         }
221 
222       }
223 
224     }
225 
226     throw new ClassNotFoundException("Cannot find class: " + name);
227 
228   }
229 
230   ClassLoader[] getClassLoaders(ClassLoader classLoader) {
231     return new ClassLoader[] { classLoader, defaultClassLoader, Thread.currentThread().getContextClassLoader(),
232         getClass().getClassLoader(), systemClassLoader };
233   }
234 
235 }