001    /**
002     * Copyright (c) 2000-present 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    /**
029     * @author Brian Wing Shun Chan
030     */
031    public class ClassLoaderProxy {
032    
033            public ClassLoaderProxy(Object obj, ClassLoader classLoader) {
034                    this(obj, obj.getClass().getName(), classLoader);
035            }
036    
037            public ClassLoaderProxy(
038                    Object obj, String className, ClassLoader classLoader) {
039    
040                    _obj = obj;
041                    _className = className;
042                    _classLoader = classLoader;
043            }
044    
045            public ClassLoader getClassLoader() {
046                    return _classLoader;
047            }
048    
049            public String getClassName() {
050                    return _className;
051            }
052    
053            public Object invoke(MethodHandler methodHandler) throws Throwable {
054                    Thread currentThread = Thread.currentThread();
055    
056                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
057    
058                    try {
059                            currentThread.setContextClassLoader(_classLoader);
060    
061                            return _invoke(methodHandler);
062                    }
063                    catch (InvocationTargetException ite) {
064                            throw translateThrowable(ite.getCause(), contextClassLoader);
065                    }
066                    catch (Throwable t) {
067                            _log.error(t, t);
068    
069                            throw t;
070                    }
071                    finally {
072                            currentThread.setContextClassLoader(contextClassLoader);
073                    }
074            }
075    
076            protected Throwable translateThrowable(
077                    Throwable throwable, ClassLoader contextClassLoader) {
078    
079                    try {
080                            UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
081                                    new UnsyncByteArrayOutputStream();
082    
083                            try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(
084                                            unsyncByteArrayOutputStream)) {
085    
086                                    objectOutputStream.writeObject(throwable);
087    
088                                    objectOutputStream.flush();
089                            }
090    
091                            UnsyncByteArrayInputStream unsyncByteArrayInputStream =
092                                    new UnsyncByteArrayInputStream(
093                                            unsyncByteArrayOutputStream.unsafeGetByteArray(), 0,
094                                            unsyncByteArrayOutputStream.size());
095    
096                            try (ObjectInputStream objectInputStream =
097                                            new ClassLoaderObjectInputStream(
098                                                    unsyncByteArrayInputStream, contextClassLoader)) {
099    
100                                    return (Throwable)objectInputStream.readObject();
101                            }
102                    }
103                    catch (Throwable throwable2) {
104                            _log.error(throwable2, throwable2);
105    
106                            return throwable2;
107                    }
108            }
109    
110            private Object _invoke(MethodHandler methodHandler) throws Exception {
111                    try {
112                            return methodHandler.invoke(_obj);
113                    }
114                    catch (NoSuchMethodException nsme) {
115                            MethodKey methodKey = methodHandler.getMethodKey();
116    
117                            String name = methodKey.getMethodName();
118    
119                            Class<?>[] parameterTypes = methodKey.getParameterTypes();
120    
121                            Class<?> clazz = Class.forName(_className, true, _classLoader);
122    
123                            for (Method method : clazz.getMethods()) {
124                                    String curName = method.getName();
125                                    Class<?>[] curParameterTypes = method.getParameterTypes();
126    
127                                    if (!curName.equals(name) ||
128                                            (curParameterTypes.length != parameterTypes.length)) {
129    
130                                            continue;
131                                    }
132    
133                                    boolean correctParams = true;
134    
135                                    for (int j = 0; j < parameterTypes.length; j++) {
136                                            Class<?> a = parameterTypes[j];
137                                            Class<?> b = curParameterTypes[j];
138    
139                                            if (!ClassUtil.isSubclass(a, b.getName())) {
140                                                    correctParams = false;
141    
142                                                    break;
143                                            }
144                                    }
145    
146                                    if (correctParams) {
147                                            return method.invoke(_obj, methodHandler.getArguments());
148                                    }
149                            }
150    
151                            throw nsme;
152                    }
153            }
154    
155            private static final Log _log = LogFactoryUtil.getLog(
156                    ClassLoaderProxy.class);
157    
158            private final ClassLoader _classLoader;
159            private final String _className;
160            private final Object _obj;
161    
162    }