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 }