001    /**
002     * Copyright (c) 2000-2012 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.test;
016    
017    import java.io.File;
018    
019    import java.lang.reflect.Constructor;
020    
021    import java.net.URI;
022    import java.net.URL;
023    import java.net.URLClassLoader;
024    
025    import java.util.ArrayList;
026    import java.util.List;
027    import java.util.concurrent.Callable;
028    
029    /**
030     * @author Shuyang Zhou
031     */
032    public class NewClassLoaderTestCase extends TestCase {
033    
034            @Override
035            public void setUp() throws Exception {
036                    String pathsString = System.getProperty("java.class.path");
037    
038                    String[] paths = pathsString.split(File.pathSeparator);
039    
040                    List<URL> urlsList = new ArrayList<URL>();
041    
042                    for (String path : paths) {
043                            File file = new File(path);
044    
045                            URI uri = file.toURI();
046    
047                            urlsList.add(uri.toURL());
048                    }
049    
050                    urls = urlsList.toArray(new URL[urlsList.size()]);
051            }
052    
053            protected <T> T runInNewClassLoader(Class<? extends Callable<T>> clazz)
054                    throws Exception {
055    
056                    assertSame(
057                            clazz + " is not enclosed by " + getClass(), getClass(),
058                            clazz.getEnclosingClass());
059    
060                    Constructor<? extends Callable<T>> constructor = null;
061    
062                    try {
063                            constructor = clazz.getDeclaredConstructor();
064                    }
065                    catch (NoSuchMethodException nsme1) {
066                            try {
067                                    constructor = clazz.getDeclaredConstructor(getClass());
068                            }
069                            catch (NoSuchMethodException nsme2) {
070                                    throw new Exception(
071                                            clazz.getName() + " does not have a default constructor");
072                            }
073                    }
074    
075                    return runInNewClassLoader(constructor);
076            }
077    
078            protected <T> T runInNewClassLoader(
079                            Constructor<? extends Callable<T>> constructor, Object... arguments)
080                    throws Exception {
081    
082                    // Prepare new class loader
083    
084                    URLClassLoader urlClassLoader = new URLClassLoader(urls, null);
085    
086                    // Get loaded class
087    
088                    Class<? extends Callable<T>> callableClass =
089                            constructor.getDeclaringClass();
090    
091                    assertSame(
092                            callableClass + " is not enclosed by " + getClass(), getClass(),
093                            callableClass.getEnclosingClass());
094    
095                    // Reload class with new class loader
096    
097                    callableClass = (Class<? extends Callable<T>>)urlClassLoader.loadClass(
098                            callableClass.getName());
099    
100                    // Reload constructor paramter types
101    
102                    Class<?>[] parameterTypes = constructor.getParameterTypes();
103    
104                    for (int i = 0; i < parameterTypes.length; i++) {
105                            parameterTypes[i] = urlClassLoader.loadClass(
106                                    parameterTypes[i].getName());
107                    }
108    
109                    // Refetch constructor
110    
111                    constructor = callableClass.getDeclaredConstructor(parameterTypes);
112    
113                    // Inner class requires outter reference
114    
115                    if (parameterTypes.length > arguments.length) {
116    
117                            // Reload outter class with new class loader
118    
119                            Class<?> outterClass = urlClassLoader.loadClass(
120                                    getClass().getName());
121    
122                            // Create outter object for the inner class instance
123    
124                            Object outterObject = outterClass.newInstance();
125    
126                            Object[] newArguments = new Object[arguments.length + 1];
127    
128                            newArguments[0] = outterObject;
129    
130                            System.arraycopy(arguments, 0, newArguments, 1, arguments.length);
131    
132                            arguments = newArguments;
133                    }
134    
135                    constructor.setAccessible(true);
136    
137                    // Create callable instance that is fully loaded by the new class loader
138    
139                    Callable<T> callable = constructor.newInstance(arguments);
140    
141                    // Run callable with new class loader
142    
143                    Thread currentThread = Thread.currentThread();
144    
145                    ClassLoader classLoader = currentThread.getContextClassLoader();
146    
147                    try {
148                            currentThread.setContextClassLoader(urlClassLoader);
149    
150                            return callable.call();
151                    }
152                    finally {
153                            currentThread.setContextClassLoader(classLoader);
154                    }
155            }
156    
157            protected URL[] urls;
158    
159    }