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.Object;
026    import java.lang.reflect.InvocationTargetException;
027    import java.lang.reflect.Method;
028    
029    import java.util.ArrayList;
030    import java.util.List;
031    
032    /**
033     * @author Brian Wing Shun Chan
034     */
035    public class ClassLoaderProxy {
036    
037            /**
038             * @deprecated
039             */
040            public ClassLoaderProxy(Object obj, ClassLoader classLoader) {
041                    this(obj, obj.getClass().getName(), classLoader);
042            }
043    
044            public ClassLoaderProxy(
045                    Object obj, String className, ClassLoader classLoader) {
046    
047                    _obj = obj;
048                    _className = className;
049                    _classLoader = classLoader;
050            }
051    
052            public ClassLoader getClassLoader() {
053                    return _classLoader;
054            }
055    
056            public Object invoke(String methodName, Object[] args) throws Throwable {
057                    Thread currentThread = Thread.currentThread();
058    
059                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
060    
061                    try {
062                            currentThread.setContextClassLoader(_classLoader);
063    
064                            Class<?> classObj = Class.forName(_className, true, _classLoader);
065    
066                            List<Class<?>> parameterTypes = new ArrayList<Class<?>>();
067    
068                            for (int i = 0; i < args.length; i++) {
069                                    Object arg = args[i];
070    
071                                    Class<?> argClass = Class.forName(
072                                            arg.getClass().getName(), true, _classLoader);
073    
074                                    if (ClassUtil.isSubclass(argClass, PrimitiveWrapper.class)) {
075                                            MethodKey methodKey = new MethodKey(
076                                                    argClass.getName(), "getValue", null);
077    
078                                            Method method = MethodCache.get(methodKey);
079    
080                                            args[i] = method.invoke(arg, (Object[])null);
081    
082                                            argClass = (Class<?>)argClass.getField("TYPE").get(arg);
083                                    }
084    
085                                    if (ClassUtil.isSubclass(argClass, NullWrapper.class)) {
086                                            NullWrapper nullWrapper = (NullWrapper)arg;
087    
088                                            argClass = Class.forName(
089                                                    nullWrapper.getClassName(), true, _classLoader);
090    
091                                            args[i] = null;
092                                    }
093    
094                                    parameterTypes.add(argClass);
095                            }
096    
097                            Method method = null;
098    
099                            try {
100                                    method = classObj.getMethod(
101                                            methodName,
102                                            parameterTypes.toArray(new Class[parameterTypes.size()]));
103                            }
104                            catch (NoSuchMethodException nsme) {
105                                    Method[] methods = ((Class<?>)classObj).getMethods();
106    
107                                    for (int i = 0; i < methods.length; i++) {
108                                            Class<?>[] methodParameterTypes =
109                                                    methods[i].getParameterTypes();
110    
111                                            if (methods[i].getName().equals(methodName) &&
112                                                    methodParameterTypes.length == parameterTypes.size()) {
113    
114                                                    boolean correctParams = true;
115    
116                                                    for (int j = 0; j < parameterTypes.size(); j++) {
117                                                            Class<?> a = parameterTypes.get(j);
118                                                            Class<?> b = methodParameterTypes[j];
119    
120                                                            if (!ClassUtil.isSubclass(a, b)) {
121                                                                    correctParams = false;
122    
123                                                                    break;
124                                                            }
125                                                    }
126    
127                                                    if (correctParams) {
128                                                            method = methods[i];
129    
130                                                            break;
131                                                    }
132                                            }
133                                    }
134    
135                                    if (method == null) {
136                                            throw nsme;
137                                    }
138                            }
139    
140                            return method.invoke(_obj, args);
141                    }
142                    catch (InvocationTargetException ite) {
143                            throw translateThrowable(ite.getCause(), contextClassLoader);
144                    }
145                    catch (Throwable t) {
146                            _log.error(t, t);
147    
148                            throw t;
149                    }
150                    finally {
151                            currentThread.setContextClassLoader(contextClassLoader);
152                    }
153            }
154    
155            protected Throwable translateThrowable(
156                    Throwable t1, ClassLoader contextClassLoader) {
157    
158                    try {
159                            UnsyncByteArrayOutputStream ubaos =
160                                    new UnsyncByteArrayOutputStream();
161                            ObjectOutputStream oos = new ObjectOutputStream(ubaos);
162    
163                            oos.writeObject(t1);
164    
165                            oos.flush();
166                            oos.close();
167    
168                            UnsyncByteArrayInputStream bais = new UnsyncByteArrayInputStream(
169                                    ubaos.unsafeGetByteArray(), 0, ubaos.size());
170                            ObjectInputStream ois = new ClassLoaderObjectInputStream(
171                                    bais, contextClassLoader);
172    
173                            t1 = (Throwable)ois.readObject();
174    
175                            ois.close();
176    
177                            return t1;
178                    }
179                    catch (Throwable t2) {
180                            _log.error(t2, t2);
181    
182                            return t2;
183                    }
184            }
185    
186            private static Log _log = LogFactoryUtil.getLog(ClassLoaderProxy.class);
187    
188            private Object _obj;
189            private ClassLoader _classLoader;
190            private String _className;
191    
192    }