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.io.unsync.UnsyncByteArrayInputStream;
18  import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
19  import com.liferay.portal.kernel.log.Log;
20  import com.liferay.portal.kernel.log.LogFactoryUtil;
21  
22  import java.io.ObjectInputStream;
23  import java.io.ObjectOutputStream;
24  
25  import java.lang.reflect.InvocationTargetException;
26  import java.lang.reflect.Method;
27  
28  import java.util.ArrayList;
29  import java.util.List;
30  
31  /**
32   * <a href="ClassLoaderProxy.java.html"><b><i>View Source</i></b></a>
33   *
34   * @author Brian Wing Shun Chan
35   */
36  public class ClassLoaderProxy {
37  
38      public ClassLoaderProxy(Object obj, ClassLoader classLoader) {
39          this(obj, obj.getClass().getName(), classLoader);
40      }
41  
42      public ClassLoaderProxy(
43          Object obj, String className, ClassLoader classLoader) {
44  
45          _obj = obj;
46          _className = className;
47          _classLoader = classLoader;
48      }
49  
50      public ClassLoader getClassLoader() {
51          return _classLoader;
52      }
53  
54      public String getClassName() {
55          return _className;
56      }
57  
58      public Object invoke(MethodHandler methodHandler) throws Throwable {
59          Thread currentThread = Thread.currentThread();
60  
61          ClassLoader contextClassLoader = currentThread.getContextClassLoader();
62  
63          try {
64              currentThread.setContextClassLoader(_classLoader);
65  
66              return _invoke(methodHandler);
67          }
68          catch (InvocationTargetException ite) {
69              throw translateThrowable(ite.getCause(), contextClassLoader);
70          }
71          catch (Throwable t) {
72              _log.error(t, t);
73  
74              throw t;
75          }
76          finally {
77              currentThread.setContextClassLoader(contextClassLoader);
78          }
79      }
80  
81      /**
82       * @deprecated
83       */
84      public Object invoke(String methodName, Object[] args) throws Throwable {
85          Thread currentThread = Thread.currentThread();
86  
87          ClassLoader contextClassLoader = currentThread.getContextClassLoader();
88  
89          try {
90              currentThread.setContextClassLoader(_classLoader);
91  
92              Class<?> classObj = Class.forName(_className, true, _classLoader);
93  
94              List<Class<?>> parameterTypes = new ArrayList<Class<?>>();
95  
96              for (int i = 0; i < args.length; i++) {
97                  Object arg = args[i];
98  
99                  Class<?> argClass = Class.forName(
100                     arg.getClass().getName(), true, _classLoader);
101 
102                 if (ClassUtil.isSubclass(argClass, PrimitiveWrapper.class)) {
103                     MethodKey methodKey = new MethodKey(
104                         argClass.getName(), "getValue");
105 
106                     Method method = MethodCache.get(methodKey);
107 
108                     args[i] = method.invoke(arg, (Object[])null);
109 
110                     argClass = (Class<?>)argClass.getField("TYPE").get(arg);
111                 }
112 
113                 if (ClassUtil.isSubclass(argClass, NullWrapper.class)) {
114                     NullWrapper nullWrapper = (NullWrapper)arg;
115 
116                     argClass = Class.forName(
117                         nullWrapper.getClassName(), true, _classLoader);
118 
119                     args[i] = null;
120                 }
121 
122                 parameterTypes.add(argClass);
123             }
124 
125             Method method = null;
126 
127             try {
128                 method = classObj.getMethod(
129                     methodName,
130                     parameterTypes.toArray(new Class[parameterTypes.size()]));
131             }
132             catch (NoSuchMethodException nsme) {
133                 Method[] methods = ((Class<?>)classObj).getMethods();
134 
135                 for (int i = 0; i < methods.length; i++) {
136                     Class<?>[] methodParameterTypes =
137                         methods[i].getParameterTypes();
138 
139                     if (methods[i].getName().equals(methodName) &&
140                         methodParameterTypes.length == parameterTypes.size()) {
141 
142                         boolean correctParams = true;
143 
144                         for (int j = 0; j < parameterTypes.size(); j++) {
145                             Class<?> a = parameterTypes.get(j);
146                             Class<?> b = methodParameterTypes[j];
147 
148                             if (!ClassUtil.isSubclass(a, b)) {
149                                 correctParams = false;
150 
151                                 break;
152                             }
153                         }
154 
155                         if (correctParams) {
156                             method = methods[i];
157 
158                             break;
159                         }
160                     }
161                 }
162 
163                 if (method == null) {
164                     throw nsme;
165                 }
166             }
167 
168             return method.invoke(_obj, args);
169         }
170         catch (InvocationTargetException ite) {
171             throw translateThrowable(ite.getCause(), contextClassLoader);
172         }
173         catch (Throwable t) {
174             _log.error(t, t);
175 
176             throw t;
177         }
178         finally {
179             currentThread.setContextClassLoader(contextClassLoader);
180         }
181     }
182 
183     protected Throwable translateThrowable(
184         Throwable t1, ClassLoader contextClassLoader) {
185 
186         try {
187             UnsyncByteArrayOutputStream ubaos =
188                 new UnsyncByteArrayOutputStream();
189             ObjectOutputStream oos = new ObjectOutputStream(ubaos);
190 
191             oos.writeObject(t1);
192 
193             oos.flush();
194             oos.close();
195 
196             UnsyncByteArrayInputStream bais = new UnsyncByteArrayInputStream(
197                 ubaos.unsafeGetByteArray(), 0, ubaos.size());
198             ObjectInputStream ois = new ClassLoaderObjectInputStream(
199                 bais, contextClassLoader);
200 
201             t1 = (Throwable)ois.readObject();
202 
203             ois.close();
204 
205             return t1;
206         }
207         catch (Throwable t2) {
208             _log.error(t2, t2);
209 
210             return t2;
211         }
212     }
213 
214     private Object _invoke(MethodHandler methodHandler) throws Exception {
215         try {
216             return methodHandler.invoke(_obj);
217         }
218         catch (NoSuchMethodException nsme) {
219             String name = methodHandler.getMethodName();
220             Class<?>[] parameterTypes = methodHandler.getArgumentsClasses();
221 
222             Class<?> classObj = Class.forName(_className, true, _classLoader);
223 
224             for (Method method : classObj.getMethods()) {
225                 String curName = method.getName();
226                 Class<?>[] curParameterTypes = method.getParameterTypes();
227 
228                 if (!curName.equals(name) ||
229                     (curParameterTypes.length != parameterTypes.length)) {
230 
231                     continue;
232                 }
233 
234                 boolean correctParams = true;
235 
236                 for (int j = 0; j < parameterTypes.length; j++) {
237                     Class<?> a = parameterTypes[j];
238                     Class<?> b = curParameterTypes[j];
239 
240                     if (!ClassUtil.isSubclass(a, b.getName())) {
241                         correctParams = false;
242 
243                         break;
244                     }
245                 }
246 
247                 if (correctParams) {
248                     return method.invoke(_obj, methodHandler.getArguments());
249                 }
250             }
251 
252             throw nsme;
253         }
254     }
255 
256     private static Log _log = LogFactoryUtil.getLog(ClassLoaderProxy.class);
257 
258     private Object _obj;
259     private ClassLoader _classLoader;
260     private String _className;
261 
262 }