001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
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    /**
032     * @author Brian Wing Shun Chan
033     */
034    public class ClassLoaderProxy {
035    
036            /**
037             * @deprecated
038             */
039            public ClassLoaderProxy(Object obj, ClassLoader classLoader) {
040                    this(obj, obj.getClass().getName(), classLoader);
041            }
042    
043            public ClassLoaderProxy(
044                    Object obj, String className, ClassLoader classLoader) {
045    
046                    _obj = obj;
047                    _className = className;
048                    _classLoader = classLoader;
049            }
050    
051            public ClassLoader getClassLoader() {
052                    return _classLoader;
053            }
054    
055            public String getClassName() {
056                    return _className;
057            }
058    
059            public Object invoke(MethodHandler methodHandler) throws Throwable {
060                    Thread currentThread = Thread.currentThread();
061    
062                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
063    
064                    try {
065                            currentThread.setContextClassLoader(_classLoader);
066    
067                            return methodHandler.invoke(_obj);
068                    }
069                    catch (InvocationTargetException ite) {
070                            throw translateThrowable(ite.getCause(), contextClassLoader);
071                    }
072                    catch (Throwable t) {
073                            _log.error(t, t);
074    
075                            throw t;
076                    }
077                    finally {
078                            currentThread.setContextClassLoader(contextClassLoader);
079                    }
080            }
081    
082            /**
083             * @deprecated
084             */
085            public Object invoke(String methodName, Object[] args) throws Throwable {
086                    Thread currentThread = Thread.currentThread();
087    
088                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
089    
090                    try {
091                            currentThread.setContextClassLoader(_classLoader);
092    
093                            Class<?> classObj = Class.forName(_className, true, _classLoader);
094    
095                            List<Class<?>> parameterTypes = new ArrayList<Class<?>>();
096    
097                            for (int i = 0; i < args.length; i++) {
098                                    Object arg = args[i];
099    
100                                    Class<?> argClass = Class.forName(
101                                            arg.getClass().getName(), true, _classLoader);
102    
103                                    if (ClassUtil.isSubclass(argClass, PrimitiveWrapper.class)) {
104                                            MethodKey methodKey = new MethodKey(
105                                                    argClass.getName(), "getValue");
106    
107                                            Method method = MethodCache.get(methodKey);
108    
109                                            args[i] = method.invoke(arg, (Object[])null);
110    
111                                            argClass = (Class<?>)argClass.getField("TYPE").get(arg);
112                                    }
113    
114                                    if (ClassUtil.isSubclass(argClass, NullWrapper.class)) {
115                                            NullWrapper nullWrapper = (NullWrapper)arg;
116    
117                                            argClass = Class.forName(
118                                                    nullWrapper.getClassName(), true, _classLoader);
119    
120                                            args[i] = null;
121                                    }
122    
123                                    parameterTypes.add(argClass);
124                            }
125    
126                            Method method = null;
127    
128                            try {
129                                    method = classObj.getMethod(
130                                            methodName,
131                                            parameterTypes.toArray(new Class[parameterTypes.size()]));
132                            }
133                            catch (NoSuchMethodException nsme) {
134                                    Method[] methods = ((Class<?>)classObj).getMethods();
135    
136                                    for (int i = 0; i < methods.length; i++) {
137                                            Class<?>[] methodParameterTypes =
138                                                    methods[i].getParameterTypes();
139    
140                                            if (methods[i].getName().equals(methodName) &&
141                                                    methodParameterTypes.length == parameterTypes.size()) {
142    
143                                                    boolean correctParams = true;
144    
145                                                    for (int j = 0; j < parameterTypes.size(); j++) {
146                                                            Class<?> a = parameterTypes.get(j);
147                                                            Class<?> b = methodParameterTypes[j];
148    
149                                                            if (!ClassUtil.isSubclass(a, b)) {
150                                                                    correctParams = false;
151    
152                                                                    break;
153                                                            }
154                                                    }
155    
156                                                    if (correctParams) {
157                                                            method = methods[i];
158    
159                                                            break;
160                                                    }
161                                            }
162                                    }
163    
164                                    if (method == null) {
165                                            throw nsme;
166                                    }
167                            }
168    
169                            return method.invoke(_obj, args);
170                    }
171                    catch (InvocationTargetException ite) {
172                            throw translateThrowable(ite.getCause(), contextClassLoader);
173                    }
174                    catch (Throwable t) {
175                            _log.error(t, t);
176    
177                            throw t;
178                    }
179                    finally {
180                            currentThread.setContextClassLoader(contextClassLoader);
181                    }
182            }
183    
184            protected Throwable translateThrowable(
185                    Throwable t1, ClassLoader contextClassLoader) {
186    
187                    try {
188                            UnsyncByteArrayOutputStream ubaos =
189                                    new UnsyncByteArrayOutputStream();
190                            ObjectOutputStream oos = new ObjectOutputStream(ubaos);
191    
192                            oos.writeObject(t1);
193    
194                            oos.flush();
195                            oos.close();
196    
197                            UnsyncByteArrayInputStream bais = new UnsyncByteArrayInputStream(
198                                    ubaos.unsafeGetByteArray(), 0, ubaos.size());
199                            ObjectInputStream ois = new ClassLoaderObjectInputStream(
200                                    bais, contextClassLoader);
201    
202                            t1 = (Throwable)ois.readObject();
203    
204                            ois.close();
205    
206                            return t1;
207                    }
208                    catch (Throwable t2) {
209                            _log.error(t2, t2);
210    
211                            return t2;
212                    }
213            }
214    
215            private static Log _log = LogFactoryUtil.getLog(ClassLoaderProxy.class);
216    
217            private Object _obj;
218            private ClassLoader _classLoader;
219            private String _className;
220    
221    }