1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.kernel.util;
16  
17  import com.liferay.portal.kernel.log.Log;
18  import com.liferay.portal.kernel.log.LogFactoryUtil;
19  
20  import java.lang.ref.WeakReference;
21  import java.lang.reflect.InvocationTargetException;
22  import java.lang.reflect.Method;
23  
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.Iterator;
27  import java.util.List;
28  
29  /**
30   * <a href="AggregateClassLoader.java.html"><b><i>View Source</i></b></a>
31   *
32   * @author Brian Wing Shun Chan
33   * @author Michael C. Han
34   * @author Shuyang Zhou
35   */
36  public class AggregateClassLoader extends ClassLoader {
37  
38      public static ClassLoader getAggregateClassLoader(
39          ClassLoader parentClassLoader, ClassLoader[] classLoaders) {
40  
41          if ((classLoaders == null) || (classLoaders.length == 0)) {
42              return null;
43          }
44  
45          if (classLoaders.length == 1) {
46              return classLoaders[0];
47          }
48  
49          AggregateClassLoader aggregateClassLoader = new AggregateClassLoader(
50              parentClassLoader);
51  
52          for (ClassLoader classLoader : classLoaders) {
53              aggregateClassLoader.addClassLoader(classLoader);
54          }
55  
56          return aggregateClassLoader;
57      }
58  
59      public static ClassLoader getAggregateClassLoader(
60          ClassLoader[] classLoaders) {
61  
62          if ((classLoaders == null) || (classLoaders.length == 0)) {
63              return null;
64          }
65  
66          return getAggregateClassLoader(classLoaders[0], classLoaders);
67      }
68  
69      public AggregateClassLoader(ClassLoader classLoader) {
70          _parentClassLoaderReference = new WeakReference<ClassLoader>(
71              classLoader);
72      }
73  
74      public void addClassLoader(ClassLoader classLoader) {
75          if (getClassLoaders().contains(classLoader)) {
76              return;
77          }
78  
79          if ((classLoader instanceof AggregateClassLoader) &&
80              (classLoader.getParent().equals(getParent()))){
81  
82              AggregateClassLoader aggregateClassLoader =
83                  (AggregateClassLoader)classLoader;
84  
85              for (ClassLoader curClassLoader :
86                      aggregateClassLoader.getClassLoaders()) {
87  
88                  addClassLoader(curClassLoader);
89              }
90          }
91          else {
92              _classLoaderReferences.add(
93                  new WeakReference<ClassLoader>(classLoader));
94          }
95      }
96  
97      public void addClassLoader(ClassLoader... classLoaders) {
98          for (ClassLoader classLoader : classLoaders) {
99              addClassLoader(classLoader);
100         }
101     }
102 
103     public void addClassLoader(Collection<ClassLoader> classLoaders) {
104         for (ClassLoader classLoader : classLoaders) {
105             addClassLoader(classLoader);
106         }
107     }
108 
109     public boolean equals(Object obj) {
110         if (this == obj) {
111             return true;
112         }
113 
114         if (!(obj instanceof AggregateClassLoader)) {
115             return false;
116         }
117 
118         AggregateClassLoader aggregateClassLoader = (AggregateClassLoader)obj;
119 
120         if (_classLoaderReferences.equals(
121                 aggregateClassLoader._classLoaderReferences) &&
122             (((getParent() == null) &&
123               (aggregateClassLoader.getParent() == null)) ||
124              ((getParent() != null) &&
125               (getParent().equals(aggregateClassLoader.getParent()))))) {
126 
127             return true;
128         }
129 
130         return false;
131     }
132 
133     public List<ClassLoader> getClassLoaders() {
134         List<ClassLoader> classLoaders = new ArrayList<ClassLoader>(
135             _classLoaderReferences.size());
136 
137         Iterator<WeakReference<ClassLoader>> itr =
138             _classLoaderReferences.iterator();
139 
140         while (itr.hasNext()) {
141             WeakReference<ClassLoader> weakReference = itr.next();
142 
143             ClassLoader classLoader = weakReference.get();
144 
145             if (classLoader == null) {
146                 itr.remove();
147             }
148             else {
149                 classLoaders.add(classLoader);
150             }
151         }
152 
153         return classLoaders;
154     }
155 
156     public int hashCode() {
157         if (_classLoaderReferences != null) {
158             return _classLoaderReferences.hashCode();
159         }
160         else {
161             return 0;
162         }
163     }
164 
165     protected Class<?> findClass(String name) throws ClassNotFoundException {
166         for (ClassLoader classLoader : getClassLoaders()) {
167             try {
168                 return _findClass(classLoader, name);
169             }
170             catch (ClassNotFoundException cnfe) {
171             }
172         }
173 
174         throw new ClassNotFoundException("Unable to find class " + name);
175     }
176 
177     protected Class<?> loadClass(String name, boolean resolve)
178         throws ClassNotFoundException {
179 
180         Class<?> loadedClass = null;
181 
182         for (ClassLoader classLoader : getClassLoaders()) {
183             try {
184                 loadedClass = _loadClass(classLoader, name, resolve);
185 
186                 break;
187             }
188             catch (ClassNotFoundException cnfe) {
189             }
190         }
191 
192         if (loadedClass == null) {
193             ClassLoader parentClassLoader = _parentClassLoaderReference.get();
194 
195             if (parentClassLoader == null) {
196                 throw new ClassNotFoundException(
197                     "Parent class loader has been garbage collected");
198             }
199 
200             loadedClass = _loadClass(parentClassLoader, name, resolve);
201         }
202         else if (resolve) {
203             resolveClass(loadedClass);
204         }
205 
206         return loadedClass;
207     }
208 
209     private static Log _log = LogFactoryUtil.getLog(AggregateClassLoader.class);
210 
211     private List<WeakReference<ClassLoader>> _classLoaderReferences =
212         new ArrayList<WeakReference<ClassLoader>>();
213 
214     private static Class<?> _findClass(ClassLoader classLoader, String name)
215         throws ClassNotFoundException {
216 
217         try {
218             return (Class<?>) _findClassMethod.invoke(classLoader, name);
219         }
220         catch (InvocationTargetException ite) {
221             throw new ClassNotFoundException(
222                 "Unable to find class " + name, ite.getTargetException());
223         }
224         catch (Exception e) {
225             throw new ClassNotFoundException("Unable to find class " + name, e);
226         }
227     }
228 
229     private static Class<?> _loadClass(
230             ClassLoader classLoader, String name, boolean resolve)
231         throws ClassNotFoundException {
232 
233         try {
234             return (Class<?>) _loadClassMethod.invoke(
235                 classLoader, name, resolve);
236         }
237         catch (InvocationTargetException ite) {
238             throw new ClassNotFoundException(
239                 "Unable to load class " + name, ite.getTargetException());
240         }
241         catch (Exception e) {
242             throw new ClassNotFoundException(
243                 "Unable to load class " + name, e);
244         }
245     }
246 
247     private static Method _findClassMethod;
248     private static Method _loadClassMethod;
249 
250     private WeakReference<ClassLoader> _parentClassLoaderReference;
251 
252     static {
253         try {
254             _findClassMethod = ReflectionUtil.getDeclaredMethod(
255                 ClassLoader.class, "findClass", String.class);
256             _loadClassMethod = ReflectionUtil.getDeclaredMethod(
257                 ClassLoader.class, "loadClass", String.class, boolean.class);
258         }
259         catch (Exception e) {
260             if (_log.isErrorEnabled()) {
261                 _log.error("Unable to locate required methods", e);
262             }
263         }
264     }
265 
266 }