001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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            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 methodHandler.invoke(_obj);
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            /**
080             * @deprecated
081             */
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<?> classObj = 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(
102                                                    argClass.getName(), "getValue");
103    
104                                            Method method = MethodCache.get(methodKey);
105    
106                                            args[i] = method.invoke(arg, (Object[])null);
107    
108                                            argClass = (Class<?>)argClass.getField("TYPE").get(arg);
109                                    }
110    
111                                    if (ClassUtil.isSubclass(argClass, NullWrapper.class)) {
112                                            NullWrapper nullWrapper = (NullWrapper)arg;
113    
114                                            argClass = Class.forName(
115                                                    nullWrapper.getClassName(), true, _classLoader);
116    
117                                            args[i] = null;
118                                    }
119    
120                                    parameterTypes.add(argClass);
121                            }
122    
123                            Method method = null;
124    
125                            try {
126                                    method = classObj.getMethod(
127                                            methodName,
128                                            parameterTypes.toArray(new Class[parameterTypes.size()]));
129                            }
130                            catch (NoSuchMethodException nsme) {
131                                    Method[] methods = ((Class<?>)classObj).getMethods();
132    
133                                    for (int i = 0; i < methods.length; i++) {
134                                            Class<?>[] methodParameterTypes =
135                                                    methods[i].getParameterTypes();
136    
137                                            if (methods[i].getName().equals(methodName) &&
138                                                    methodParameterTypes.length == 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 t1, ClassLoader contextClassLoader) {
183    
184                    try {
185                            UnsyncByteArrayOutputStream ubaos =
186                                    new UnsyncByteArrayOutputStream();
187                            ObjectOutputStream oos = new ObjectOutputStream(ubaos);
188    
189                            oos.writeObject(t1);
190    
191                            oos.flush();
192                            oos.close();
193    
194                            UnsyncByteArrayInputStream bais = new UnsyncByteArrayInputStream(
195                                    ubaos.unsafeGetByteArray(), 0, ubaos.size());
196                            ObjectInputStream ois = new ClassLoaderObjectInputStream(
197                                    bais, contextClassLoader);
198    
199                            t1 = (Throwable)ois.readObject();
200    
201                            ois.close();
202    
203                            return t1;
204                    }
205                    catch (Throwable t2) {
206                            _log.error(t2, t2);
207    
208                            return t2;
209                    }
210            }
211    
212            private static Log _log = LogFactoryUtil.getLog(ClassLoaderProxy.class);
213    
214            private Object _obj;
215            private ClassLoader _classLoader;
216            private String _className;
217    
218    }