001
014
015 package com.liferay.portal.kernel.util;
016
017 import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
018 import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
019 import com.liferay.portal.kernel.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021
022 import java.io.ObjectInputStream;
023 import java.io.ObjectOutputStream;
024
025 import java.lang.reflect.InvocationTargetException;
026 import java.lang.reflect.Method;
027
028 import java.util.ArrayList;
029 import java.util.List;
030
031
034 public class ClassLoaderProxy {
035
036 public ClassLoaderProxy(Object obj, ClassLoader classLoader) {
037 this(obj, obj.getClass().getName(), classLoader);
038 }
039
040 public ClassLoaderProxy(
041 Object obj, String className, ClassLoader classLoader) {
042
043 _obj = obj;
044 _className = className;
045 _classLoader = classLoader;
046 }
047
048 public ClassLoader getClassLoader() {
049 return _classLoader;
050 }
051
052 public String getClassName() {
053 return _className;
054 }
055
056 public Object invoke(MethodHandler methodHandler) throws Throwable {
057 Thread currentThread = Thread.currentThread();
058
059 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
060
061 try {
062 currentThread.setContextClassLoader(_classLoader);
063
064 return _invoke(methodHandler);
065 }
066 catch (InvocationTargetException ite) {
067 throw translateThrowable(ite.getCause(), contextClassLoader);
068 }
069 catch (Throwable t) {
070 _log.error(t, t);
071
072 throw t;
073 }
074 finally {
075 currentThread.setContextClassLoader(contextClassLoader);
076 }
077 }
078
079
082 public Object invoke(String methodName, Object[] args) throws Throwable {
083 Thread currentThread = Thread.currentThread();
084
085 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
086
087 try {
088 currentThread.setContextClassLoader(_classLoader);
089
090 Class<?> clazz = Class.forName(_className, true, _classLoader);
091
092 List<Class<?>> parameterTypes = new ArrayList<Class<?>>();
093
094 for (int i = 0; i < args.length; i++) {
095 Object arg = args[i];
096
097 Class<?> argClass = Class.forName(
098 arg.getClass().getName(), true, _classLoader);
099
100 if (ClassUtil.isSubclass(argClass, PrimitiveWrapper.class)) {
101 MethodKey methodKey = new MethodKey(argClass, "getValue");
102
103 Method method = methodKey.getMethod();
104
105 args[i] = method.invoke(arg, (Object[])null);
106
107 argClass = (Class<?>)argClass.getField("TYPE").get(arg);
108 }
109
110 if (ClassUtil.isSubclass(argClass, NullWrapper.class)) {
111 NullWrapper nullWrapper = (NullWrapper)arg;
112
113 argClass = Class.forName(
114 nullWrapper.getClassName(), true, _classLoader);
115
116 args[i] = null;
117 }
118
119 parameterTypes.add(argClass);
120 }
121
122 Method method = null;
123
124 try {
125 method = clazz.getMethod(
126 methodName,
127 parameterTypes.toArray(new Class[parameterTypes.size()]));
128 }
129 catch (NoSuchMethodException nsme) {
130 Method[] methods = ((Class<?>)clazz).getMethods();
131
132 for (int i = 0; i < methods.length; i++) {
133 Class<?>[] methodParameterTypes =
134 methods[i].getParameterTypes();
135
136 if (methods[i].getName().equals(methodName) &&
137 (methodParameterTypes.length ==
138 parameterTypes.size())) {
139
140 boolean correctParams = true;
141
142 for (int j = 0; j < parameterTypes.size(); j++) {
143 Class<?> a = parameterTypes.get(j);
144 Class<?> b = methodParameterTypes[j];
145
146 if (!ClassUtil.isSubclass(a, b)) {
147 correctParams = false;
148
149 break;
150 }
151 }
152
153 if (correctParams) {
154 method = methods[i];
155
156 break;
157 }
158 }
159 }
160
161 if (method == null) {
162 throw nsme;
163 }
164 }
165
166 return method.invoke(_obj, args);
167 }
168 catch (InvocationTargetException ite) {
169 throw translateThrowable(ite.getCause(), contextClassLoader);
170 }
171 catch (Throwable t) {
172 _log.error(t, t);
173
174 throw t;
175 }
176 finally {
177 currentThread.setContextClassLoader(contextClassLoader);
178 }
179 }
180
181 protected Throwable translateThrowable(
182 Throwable throwable, ClassLoader contextClassLoader) {
183
184 try {
185 UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
186 new UnsyncByteArrayOutputStream();
187 ObjectOutputStream objectOutputStream = new ObjectOutputStream(
188 unsyncByteArrayOutputStream);
189
190 objectOutputStream.writeObject(throwable);
191
192 objectOutputStream.flush();
193 objectOutputStream.close();
194
195 UnsyncByteArrayInputStream unsyncByteArrayInputStream =
196 new UnsyncByteArrayInputStream(
197 unsyncByteArrayOutputStream.unsafeGetByteArray(), 0,
198 unsyncByteArrayOutputStream.size());
199 ObjectInputStream objectInputStream =
200 new ClassLoaderObjectInputStream(
201 unsyncByteArrayInputStream, contextClassLoader);
202
203 throwable = (Throwable)objectInputStream.readObject();
204
205 objectInputStream.close();
206
207 return throwable;
208 }
209 catch (Throwable throwable2) {
210 _log.error(throwable2, throwable2);
211
212 return throwable2;
213 }
214 }
215
216 private Object _invoke(MethodHandler methodHandler) throws Exception {
217 try {
218 return methodHandler.invoke(_obj);
219 }
220 catch (NoSuchMethodException nsme) {
221 MethodKey methodKey = methodHandler.getMethodKey();
222
223 String name = methodKey.getMethodName();
224
225 Class<?>[] parameterTypes = methodKey.getParameterTypes();
226
227 Class<?> clazz = Class.forName(_className, true, _classLoader);
228
229 for (Method method : clazz.getMethods()) {
230 String curName = method.getName();
231 Class<?>[] curParameterTypes = method.getParameterTypes();
232
233 if (!curName.equals(name) ||
234 (curParameterTypes.length != parameterTypes.length)) {
235
236 continue;
237 }
238
239 boolean correctParams = true;
240
241 for (int j = 0; j < parameterTypes.length; j++) {
242 Class<?> a = parameterTypes[j];
243 Class<?> b = curParameterTypes[j];
244
245 if (!ClassUtil.isSubclass(a, b.getName())) {
246 correctParams = false;
247
248 break;
249 }
250 }
251
252 if (correctParams) {
253 return method.invoke(_obj, methodHandler.getArguments());
254 }
255 }
256
257 throw nsme;
258 }
259 }
260
261 private static Log _log = LogFactoryUtil.getLog(ClassLoaderProxy.class);
262
263 private ClassLoader _classLoader;
264 private String _className;
265 private Object _obj;
266
267 }