1
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
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
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 }