View Javadoc
1   /*
2    *    Copyright 2010-2026 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.migration.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  public class ClassLoaderWrapper {
25  
26    ClassLoader defaultClassLoader;
27    ClassLoader systemClassLoader;
28  
29    ClassLoaderWrapper() {
30      try {
31        systemClassLoader = ClassLoader.getSystemClassLoader();
32      } catch (SecurityException ignored) {
33        // AccessControlException on Google App Engine
34      }
35    }
36  
37    /**
38     * Get a resource as a URL using the current class path
39     *
40     * @param resource
41     *          - the resource to locate
42     *
43     * @return the resource or null
44     */
45    public URL getResourceAsURL(String resource) {
46      return getResourceAsURL(resource, getClassLoaders(null));
47    }
48  
49    /**
50     * Get a resource from the classpath, starting with a specific class loader
51     *
52     * @param resource
53     *          - the resource to find
54     * @param classLoader
55     *          - the first classloader to try
56     *
57     * @return the stream or null
58     */
59    public URL getResourceAsURL(String resource, ClassLoader classLoader) {
60      return getResourceAsURL(resource, getClassLoaders(classLoader));
61    }
62  
63    /**
64     * Get a resource from the classpath
65     *
66     * @param resource
67     *          - the resource to find
68     *
69     * @return the stream or null
70     */
71    public InputStream getResourceAsStream(String resource) {
72      return getResourceAsStream(resource, getClassLoaders(null));
73    }
74  
75    /**
76     * Get a resource from the classpath, starting with a specific class loader
77     *
78     * @param resource
79     *          - the resource to find
80     * @param classLoader
81     *          - the first class loader to try
82     *
83     * @return the stream or null
84     */
85    public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
86      return getResourceAsStream(resource, getClassLoaders(classLoader));
87    }
88  
89    /**
90     * Find a class on the classpath (or die trying)
91     *
92     * @param name
93     *          - the class to look for
94     *
95     * @return - the class
96     *
97     * @throws ClassNotFoundException
98     *           Duh.
99     */
100   public Class<?> classForName(String name) throws ClassNotFoundException {
101     return classForName(name, getClassLoaders(null));
102   }
103 
104   /**
105    * Find a class on the classpath, starting with a specific classloader (or die trying)
106    *
107    * @param name
108    *          - the class to look for
109    * @param classLoader
110    *          - the first classloader to try
111    *
112    * @return - the class
113    *
114    * @throws ClassNotFoundException
115    *           Duh.
116    */
117   public Class<?> classForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
118     return classForName(name, getClassLoaders(classLoader));
119   }
120 
121   /**
122    * Try to get a resource from a group of classloaders
123    *
124    * @param resource
125    *          - the resource to get
126    * @param classLoader
127    *          - the classloaders to examine
128    *
129    * @return the resource or null
130    */
131   InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
132     for (ClassLoader cl : classLoader) {
133       if (null != cl) {
134 
135         // try to find the resource as passed
136         InputStream returnValue = cl.getResourceAsStream(resource);
137 
138         // now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
139         if (null == returnValue) {
140           returnValue = cl.getResourceAsStream("/" + resource);
141         }
142 
143         if (null != returnValue) {
144           return returnValue;
145         }
146       }
147     }
148     return null;
149   }
150 
151   /**
152    * Get a resource as a URL using the current class path
153    *
154    * @param resource
155    *          - the resource to locate
156    * @param classLoader
157    *          - the class loaders to examine
158    *
159    * @return the resource or null
160    */
161   URL getResourceAsURL(String resource, ClassLoader[] classLoader) {
162 
163     URL url;
164 
165     for (ClassLoader cl : classLoader) {
166 
167       if (null != cl) {
168 
169         // look for the resource as passed in...
170         url = cl.getResource(resource);
171 
172         // ...but some class loaders want this leading "/", so we'll add it
173         // and try again if we didn't find the resource
174         if (null == url) {
175           url = cl.getResource("/" + resource);
176         }
177 
178         // "It's always in the last place I look for it!"
179         // ... because only an idiot would keep looking for it after finding it, so stop looking already.
180         if (null != url) {
181           return url;
182         }
183 
184       }
185 
186     }
187 
188     // didn't find it anywhere.
189     return null;
190 
191   }
192 
193   /**
194    * Attempt to load a class from a group of classloaders
195    *
196    * @param name
197    *          - the class to load
198    * @param classLoader
199    *          - the group of classloaders to examine
200    *
201    * @return the class
202    *
203    * @throws ClassNotFoundException
204    *           - Remember the wisdom of Judge Smails: Well, the world needs ditch diggers, too.
205    */
206   Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {
207 
208     for (ClassLoader cl : classLoader) {
209 
210       if (null != cl) {
211 
212         try {
213 
214           return Class.forName(name, true, cl);
215 
216         } catch (ClassNotFoundException e) {
217           // we'll ignore this until all classloaders fail to locate the class
218         }
219 
220       }
221 
222     }
223 
224     throw new ClassNotFoundException("Cannot find class: " + name);
225 
226   }
227 
228   ClassLoader[] getClassLoaders(ClassLoader classLoader) {
229     return new ClassLoader[] { classLoader, defaultClassLoader, Thread.currentThread().getContextClassLoader(),
230         getClass().getClassLoader(), systemClassLoader };
231   }
232 
233 }