001
014
015 package com.liferay.portal.kernel.util;
016
017 import com.liferay.portal.kernel.exception.LoggedExceptionInInitializerError;
018 import com.liferay.portal.kernel.memory.EqualityWeakReference;
019
020 import java.io.IOException;
021
022 import java.lang.ref.WeakReference;
023 import java.lang.reflect.InvocationTargetException;
024 import java.lang.reflect.Method;
025
026 import java.net.URL;
027
028 import java.util.ArrayList;
029 import java.util.Collection;
030 import java.util.Collections;
031 import java.util.Enumeration;
032 import java.util.Iterator;
033 import java.util.List;
034
035
040 public class AggregateClassLoader extends ClassLoader {
041
042 public static ClassLoader getAggregateClassLoader(
043 ClassLoader parentClassLoader, ClassLoader... classLoaders) {
044
045 if (ArrayUtil.isEmpty(classLoaders)) {
046 return parentClassLoader;
047 }
048
049 AggregateClassLoader aggregateClassLoader = null;
050
051 if (parentClassLoader instanceof AggregateClassLoader) {
052 aggregateClassLoader = (AggregateClassLoader)parentClassLoader;
053 }
054 else {
055 aggregateClassLoader = new AggregateClassLoader(parentClassLoader);
056 }
057
058 for (ClassLoader classLoader : classLoaders) {
059 aggregateClassLoader.addClassLoader(classLoader);
060 }
061
062 return aggregateClassLoader;
063 }
064
065 public static ClassLoader getAggregateClassLoader(
066 ClassLoader[] classLoaders) {
067
068 if (ArrayUtil.isEmpty(classLoaders)) {
069 return null;
070 }
071
072 return getAggregateClassLoader(classLoaders[0], classLoaders);
073 }
074
075 public AggregateClassLoader(ClassLoader classLoader) {
076 _parentClassLoaderReference = new WeakReference<>(classLoader);
077 }
078
079 public void addClassLoader(ClassLoader classLoader) {
080 List<ClassLoader> classLoaders = getClassLoaders();
081
082 if (classLoaders.contains(classLoader)) {
083 return;
084 }
085
086 if ((classLoader instanceof AggregateClassLoader) &&
087 classLoader.getParent().equals(getParent())) {
088
089 AggregateClassLoader aggregateClassLoader =
090 (AggregateClassLoader)classLoader;
091
092 for (ClassLoader curClassLoader :
093 aggregateClassLoader.getClassLoaders()) {
094
095 addClassLoader(curClassLoader);
096 }
097 }
098 else {
099 _classLoaderReferences.add(
100 new EqualityWeakReference<>(classLoader));
101 }
102 }
103
104 public void addClassLoader(ClassLoader... classLoaders) {
105 for (ClassLoader classLoader : classLoaders) {
106 addClassLoader(classLoader);
107 }
108 }
109
110 public void addClassLoader(Collection<ClassLoader> classLoaders) {
111 for (ClassLoader classLoader : classLoaders) {
112 addClassLoader(classLoader);
113 }
114 }
115
116 @Override
117 public boolean equals(Object obj) {
118 if (this == obj) {
119 return true;
120 }
121
122 if (!(obj instanceof AggregateClassLoader)) {
123 return false;
124 }
125
126 AggregateClassLoader aggregateClassLoader = (AggregateClassLoader)obj;
127
128 if (_classLoaderReferences.equals(
129 aggregateClassLoader._classLoaderReferences) &&
130 (((getParent() == null) &&
131 (aggregateClassLoader.getParent() == null)) ||
132 ((getParent() != null) &&
133 getParent().equals(aggregateClassLoader.getParent())))) {
134
135 return true;
136 }
137
138 return false;
139 }
140
141 public List<ClassLoader> getClassLoaders() {
142 List<ClassLoader> classLoaders = new ArrayList<>(
143 _classLoaderReferences.size());
144
145 Iterator<EqualityWeakReference<ClassLoader>> itr =
146 _classLoaderReferences.iterator();
147
148 while (itr.hasNext()) {
149 WeakReference<ClassLoader> weakReference = itr.next();
150
151 ClassLoader classLoader = weakReference.get();
152
153 if (classLoader == null) {
154 itr.remove();
155 }
156 else {
157 classLoaders.add(classLoader);
158 }
159 }
160
161 return classLoaders;
162 }
163
164 @Override
165 public URL getResource(String name) {
166 for (ClassLoader classLoader : getClassLoaders()) {
167 URL url = _getResource(classLoader, name);
168
169 if (url != null) {
170 return url;
171 }
172 }
173
174 ClassLoader parentClassLoader = _parentClassLoaderReference.get();
175
176 if (parentClassLoader == null) {
177 return null;
178 }
179
180 return parentClassLoader.getResource(name);
181 }
182
183 @Override
184 public Enumeration<URL> getResources(String name) throws IOException {
185 List<URL> urls = new ArrayList<>();
186
187 for (ClassLoader classLoader : getClassLoaders()) {
188 urls.addAll(Collections.list(_getResources(classLoader, name)));
189 }
190
191 ClassLoader parentClassLoader = _parentClassLoaderReference.get();
192
193 if (parentClassLoader != null) {
194 urls.addAll(
195 Collections.list(_getResources(parentClassLoader, name)));
196 }
197
198 return Collections.enumeration(urls);
199 }
200
201 @Override
202 public int hashCode() {
203 if (_classLoaderReferences != null) {
204 return _classLoaderReferences.hashCode();
205 }
206 else {
207 return 0;
208 }
209 }
210
211 @Override
212 protected Class<?> findClass(String name) throws ClassNotFoundException {
213 for (ClassLoader classLoader : getClassLoaders()) {
214 try {
215 return _findClass(classLoader, name);
216 }
217 catch (ClassNotFoundException cnfe) {
218 }
219 }
220
221 throw new ClassNotFoundException("Unable to find class " + name);
222 }
223
224 @Override
225 protected synchronized Class<?> loadClass(String name, boolean resolve)
226 throws ClassNotFoundException {
227
228 Class<?> loadedClass = null;
229
230 for (ClassLoader classLoader : getClassLoaders()) {
231 try {
232 loadedClass = _loadClass(classLoader, name, resolve);
233
234 break;
235 }
236 catch (ClassNotFoundException cnfe) {
237 }
238 }
239
240 if (loadedClass == null) {
241 ClassLoader parentClassLoader = _parentClassLoaderReference.get();
242
243 if (parentClassLoader == null) {
244 throw new ClassNotFoundException(
245 "Parent class loader has been garbage collected");
246 }
247
248 loadedClass = _loadClass(parentClassLoader, name, resolve);
249 }
250 else if (resolve) {
251 resolveClass(loadedClass);
252 }
253
254 return loadedClass;
255 }
256
257 private static Class<?> _findClass(ClassLoader classLoader, String name)
258 throws ClassNotFoundException {
259
260 try {
261 return (Class<?>) _FIND_CLASS_METHOD.invoke(classLoader, name);
262 }
263 catch (InvocationTargetException ite) {
264 throw new ClassNotFoundException(
265 "Unable to find class " + name, ite.getTargetException());
266 }
267 catch (Exception e) {
268 throw new ClassNotFoundException("Unable to find class " + name, e);
269 }
270 }
271
272 private static URL _getResource(ClassLoader classLoader, String name) {
273 try {
274 return (URL)_GET_RESOURCE_METHOD.invoke(classLoader, name);
275 }
276 catch (InvocationTargetException ite) {
277 return null;
278 }
279 catch (Exception e) {
280 return null;
281 }
282 }
283
284 private static Enumeration<URL> _getResources(
285 ClassLoader classLoader, String name)
286 throws IOException {
287
288 try {
289 return (Enumeration<URL>)_GET_RESOURCES_METHOD.invoke(
290 classLoader, name);
291 }
292 catch (InvocationTargetException ite) {
293 Throwable t = ite.getTargetException();
294
295 throw new IOException(t);
296 }
297 catch (Exception e) {
298 throw new IOException(e);
299 }
300 }
301
302 private static Class<?> _loadClass(
303 ClassLoader classLoader, String name, boolean resolve)
304 throws ClassNotFoundException {
305
306 try {
307 return (Class<?>)_LOAD_CLASS_METHOD.invoke(
308 classLoader, name, resolve);
309 }
310 catch (InvocationTargetException ite) {
311 throw new ClassNotFoundException(
312 "Unable to load class " + name, ite.getTargetException());
313 }
314 catch (Exception e) {
315 throw new ClassNotFoundException("Unable to load class " + name, e);
316 }
317 }
318
319 private static final Method _FIND_CLASS_METHOD;
320
321 private static final Method _GET_RESOURCE_METHOD;
322
323 private static final Method _GET_RESOURCES_METHOD;
324
325 private static final Method _LOAD_CLASS_METHOD;
326
327 static {
328 try {
329 _FIND_CLASS_METHOD = ReflectionUtil.getDeclaredMethod(
330 ClassLoader.class, "findClass", String.class);
331
332 _GET_RESOURCE_METHOD = ReflectionUtil.getDeclaredMethod(
333 ClassLoader.class, "getResource", String.class);
334
335 _GET_RESOURCES_METHOD = ReflectionUtil.getDeclaredMethod(
336 ClassLoader.class, "getResources", String.class);
337
338 _LOAD_CLASS_METHOD = ReflectionUtil.getDeclaredMethod(
339 ClassLoader.class, "loadClass", String.class, boolean.class);
340 }
341 catch (Exception e) {
342 throw new LoggedExceptionInInitializerError(e);
343 }
344 }
345
346 private final List<EqualityWeakReference<ClassLoader>>
347 _classLoaderReferences = new ArrayList<>();
348 private final WeakReference<ClassLoader> _parentClassLoaderReference;
349
350 }