001
014
015 package com.liferay.portal.kernel.util;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.memory.EqualityWeakReference;
020
021 import java.io.IOException;
022
023 import java.lang.ref.WeakReference;
024 import java.lang.reflect.InvocationTargetException;
025 import java.lang.reflect.Method;
026
027 import java.net.URL;
028
029 import java.util.ArrayList;
030 import java.util.Collection;
031 import java.util.Collections;
032 import java.util.Enumeration;
033 import java.util.Iterator;
034 import java.util.List;
035
036
041 public class AggregateClassLoader extends ClassLoader {
042
043 public static ClassLoader getAggregateClassLoader(
044 ClassLoader parentClassLoader, ClassLoader[] classLoaders) {
045
046 if (ArrayUtil.isEmpty(classLoaders)) {
047 return null;
048 }
049
050 if (classLoaders.length == 1) {
051 return classLoaders[0];
052 }
053
054 AggregateClassLoader aggregateClassLoader = new AggregateClassLoader(
055 parentClassLoader);
056
057 for (ClassLoader classLoader : classLoaders) {
058 aggregateClassLoader.addClassLoader(classLoader);
059 }
060
061 return aggregateClassLoader;
062 }
063
064 public static ClassLoader getAggregateClassLoader(
065 ClassLoader[] classLoaders) {
066
067 if (ArrayUtil.isEmpty(classLoaders)) {
068 return null;
069 }
070
071 return getAggregateClassLoader(classLoaders[0], classLoaders);
072 }
073
074 public AggregateClassLoader(ClassLoader classLoader) {
075 _parentClassLoaderReference = new WeakReference<ClassLoader>(
076 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>(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<ClassLoader>(
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<URL>();
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<?>) _findClassMethod.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)_getResourceMethod.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>)_getResourcesMethod.invoke(
290 classLoader, name);
291 }
292 catch (InvocationTargetException ite) {
293 Throwable t = ite.getTargetException();
294
295 throw new IOException(t.getMessage());
296 }
297 catch (Exception e) {
298 throw new IOException(e.getMessage());
299 }
300 }
301
302 private static Class<?> _loadClass(
303 ClassLoader classLoader, String name, boolean resolve)
304 throws ClassNotFoundException {
305
306 try {
307 return (Class<?>)_loadClassMethod.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 Log _log = LogFactoryUtil.getLog(AggregateClassLoader.class);
320
321 private static Method _findClassMethod;
322 private static Method _getResourceMethod;
323 private static Method _getResourcesMethod;
324 private static Method _loadClassMethod;
325
326 private List<EqualityWeakReference<ClassLoader>> _classLoaderReferences =
327 new ArrayList<EqualityWeakReference<ClassLoader>>();
328 private WeakReference<ClassLoader> _parentClassLoaderReference;
329
330 static {
331 try {
332 _findClassMethod = ReflectionUtil.getDeclaredMethod(
333 ClassLoader.class, "findClass", String.class);
334 _getResourceMethod = ReflectionUtil.getDeclaredMethod(
335 ClassLoader.class, "getResource", String.class);
336 _getResourcesMethod = ReflectionUtil.getDeclaredMethod(
337 ClassLoader.class, "getResources", String.class);
338 _loadClassMethod = ReflectionUtil.getDeclaredMethod(
339 ClassLoader.class, "loadClass", String.class, boolean.class);
340 }
341 catch (Exception e) {
342 if (_log.isErrorEnabled()) {
343 _log.error("Unable to locate required methods", e);
344 }
345 }
346 }
347
348 }